virtualmachine.go 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859
  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. "sort"
  20. "strings"
  21. "time"
  22. "unicode"
  23. "github.com/vmware/govmomi/nfc"
  24. "github.com/vmware/govmomi/object"
  25. "github.com/vmware/govmomi/vim25/methods"
  26. "github.com/vmware/govmomi/vim25/mo"
  27. "github.com/vmware/govmomi/vim25/soap"
  28. "github.com/vmware/govmomi/vim25/types"
  29. "yunion.io/x/jsonutils"
  30. "yunion.io/x/log"
  31. "yunion.io/x/pkg/errors"
  32. "yunion.io/x/pkg/gotypes"
  33. "yunion.io/x/pkg/util/billing"
  34. "yunion.io/x/pkg/util/imagetools"
  35. "yunion.io/x/pkg/util/netutils"
  36. "yunion.io/x/pkg/util/reflectutils"
  37. "yunion.io/x/pkg/util/regutils"
  38. "yunion.io/x/pkg/util/version"
  39. "yunion.io/x/pkg/utils"
  40. billing_api "yunion.io/x/cloudmux/pkg/apis/billing"
  41. api "yunion.io/x/cloudmux/pkg/apis/compute"
  42. "yunion.io/x/cloudmux/pkg/cloudprovider"
  43. "yunion.io/x/cloudmux/pkg/multicloud"
  44. )
  45. var (
  46. vmSummaryProps = []string{"summary.runtime.powerState", "summary.config.uuid", "summary.config.memorySizeMB", "summary.config.numCpu", "summary.customValue"}
  47. // vmConfigProps = []string{"config.template", "config.alternateGuestName", "config.hardware", "config.guestId", "config.guestFullName", "config.firmware", "config.version", "config.createDate"}
  48. vmGuestProps = []string{"guest.net", "guest.guestState", "guest.toolsStatus", "guest.toolsRunningStatus", "guest.toolsVersion"}
  49. vmLayoutExProps = []string{"layoutEx.file"}
  50. )
  51. var VIRTUAL_MACHINE_PROPS = []string{"name", "parent", "resourcePool", "snapshot", "config", "availableField", "datastore"}
  52. func init() {
  53. VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmSummaryProps...)
  54. // VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmConfigProps...)
  55. VIRTUAL_MACHINE_PROPS = append(VIRTUAL_MACHINE_PROPS, vmGuestProps...)
  56. }
  57. type SVirtualMachine struct {
  58. multicloud.SInstanceBase
  59. multicloud.STagBase
  60. SManagedObject
  61. vnics []SVirtualNIC
  62. vdisks []SVirtualDisk
  63. vga SVirtualVGA
  64. cdroms []SVirtualCdrom
  65. devs map[int32]SVirtualDevice
  66. ihost cloudprovider.ICloudHost
  67. snapshots []SVirtualMachineSnapshot
  68. guestIps map[string]sNicConfig
  69. osInfo *imagetools.ImageInfo
  70. }
  71. type VMFetcher interface {
  72. FetchNoTemplateVMs() ([]*SVirtualMachine, error)
  73. FetchTemplateVMs() ([]*SVirtualMachine, error)
  74. FetchFakeTempateVMs(string) ([]*SVirtualMachine, error)
  75. }
  76. func NewVirtualMachine(manager *SESXiClient, vm *mo.VirtualMachine, dc *SDatacenter) *SVirtualMachine {
  77. svm := &SVirtualMachine{SManagedObject: newManagedObject(manager, vm, dc)}
  78. err := svm.fetchHardwareInfo()
  79. if err != nil {
  80. log.Errorf("NewVirtualMachine: %v", err)
  81. return nil
  82. }
  83. return svm
  84. }
  85. func (svm *SVirtualMachine) GetSecurityGroupIds() ([]string, error) {
  86. return []string{}, cloudprovider.ErrNotSupported
  87. }
  88. func (svm *SVirtualMachine) GetTags() (map[string]string, error) {
  89. // not support tags
  90. if gotypes.IsNil(svm.manager.client.ServiceContent.CustomFieldsManager) {
  91. return nil, cloudprovider.ErrNotSupported
  92. }
  93. ret := map[int32]string{}
  94. for _, val := range svm.object.Entity().ExtensibleManagedObject.AvailableField {
  95. ret[val.Key] = val.Name
  96. }
  97. result := map[string]string{}
  98. vm := svm.getVirtualMachine()
  99. for _, val := range vm.Summary.CustomValue {
  100. value := struct {
  101. Key int32
  102. Value string
  103. }{}
  104. jsonutils.Update(&value, val)
  105. _, ok := ret[value.Key]
  106. if ok && len(value.Value) > 0 {
  107. result[ret[value.Key]] = value.Value
  108. }
  109. }
  110. for _, key := range ret {
  111. _, ok := result[key]
  112. if !ok {
  113. delete(result, key)
  114. }
  115. }
  116. return result, nil
  117. }
  118. func (svm *SVirtualMachine) SetTags(tags map[string]string, replace bool) error {
  119. // not support tags
  120. if gotypes.IsNil(svm.manager.client.ServiceContent.CustomFieldsManager) {
  121. return cloudprovider.ErrNotSupported
  122. }
  123. oldTags, err := svm.GetTags()
  124. if err != nil {
  125. return errors.Wrapf(err, "GetTags")
  126. }
  127. added, removed := map[string]string{}, map[string]string{}
  128. for k, v := range tags {
  129. oldValue, ok := oldTags[k]
  130. if !ok {
  131. added[k] = v
  132. } else if oldValue != v {
  133. removed[k] = oldValue
  134. added[k] = v
  135. }
  136. }
  137. if replace {
  138. for k, v := range oldTags {
  139. newValue, ok := tags[k]
  140. if !ok {
  141. removed[k] = v
  142. } else if v != newValue {
  143. added[k] = newValue
  144. removed[k] = v
  145. }
  146. }
  147. }
  148. cfm := object.NewCustomFieldsManager(svm.manager.client.Client)
  149. ctx := context.Background()
  150. for k := range removed {
  151. id, err := cfm.FindKey(ctx, k)
  152. if err != nil {
  153. if !strings.Contains(err.Error(), "not found") {
  154. return errors.Wrapf(err, "FindKey %s", k)
  155. }
  156. continue
  157. }
  158. err = cfm.Set(ctx, svm.object.Reference(), id, "")
  159. if err != nil {
  160. return errors.Wrapf(err, "Set")
  161. }
  162. }
  163. for k, v := range added {
  164. id, err := cfm.FindKey(ctx, k)
  165. if err != nil {
  166. if !strings.Contains(err.Error(), "not found") {
  167. return errors.Wrapf(err, "FindKey %s", k)
  168. }
  169. ref, err := cfm.Add(ctx, k, "VirtualMachine", nil, nil)
  170. if err != nil {
  171. return errors.Wrapf(err, "Add %s", k)
  172. }
  173. id = ref.Key
  174. }
  175. err = cfm.Set(ctx, svm.object.Reference(), id, v)
  176. if err != nil {
  177. return errors.Wrapf(err, "Set")
  178. }
  179. }
  180. return nil
  181. }
  182. func (svm *SVirtualMachine) getVirtualMachine() *mo.VirtualMachine {
  183. return svm.object.(*mo.VirtualMachine)
  184. }
  185. func (svm *SVirtualMachine) GetGlobalId() string {
  186. return svm.getUuid()
  187. }
  188. func (svm *SVirtualMachine) GetHostname() string {
  189. return ""
  190. }
  191. func (svm *SVirtualMachine) GetDescription() string {
  192. vm := svm.getVirtualMachine()
  193. if vm != nil && vm.Config != nil {
  194. return vm.Config.Annotation
  195. }
  196. return ""
  197. }
  198. func (svm *SVirtualMachine) GetStatus() string {
  199. // err := svm.CheckFileInfo(context.Background())
  200. // if err != nil {
  201. // return api.VM_UNKNOWN
  202. // }
  203. vm := object.NewVirtualMachine(svm.manager.client.Client, svm.getVirtualMachine().Self)
  204. state, err := vm.PowerState(svm.manager.context)
  205. if err != nil {
  206. return api.VM_UNKNOWN
  207. }
  208. switch state {
  209. case types.VirtualMachinePowerStatePoweredOff:
  210. return api.VM_READY
  211. case types.VirtualMachinePowerStatePoweredOn:
  212. return api.VM_RUNNING
  213. case types.VirtualMachinePowerStateSuspended:
  214. return api.VM_SUSPEND
  215. default:
  216. return api.VM_UNKNOWN
  217. }
  218. }
  219. func (svm *SVirtualMachine) Refresh() error {
  220. base := svm.SManagedObject
  221. var moObj mo.VirtualMachine
  222. err := svm.manager.reference2Object(svm.object.Reference(), VIRTUAL_MACHINE_PROPS, &moObj)
  223. if err != nil {
  224. if e := errors.Cause(err); soap.IsSoapFault(e) {
  225. _, ok := soap.ToSoapFault(e).VimFault().(types.ManagedObjectNotFound)
  226. if ok {
  227. return cloudprovider.ErrNotFound
  228. }
  229. }
  230. return err
  231. }
  232. base.object = &moObj
  233. *svm = SVirtualMachine{}
  234. svm.SManagedObject = base
  235. svm.fetchHardwareInfo()
  236. return nil
  237. }
  238. func (svm *SVirtualMachine) IsEmulated() bool {
  239. return false
  240. }
  241. func (svm *SVirtualMachine) GetInstanceType() string {
  242. return ""
  243. }
  244. func (svm *SVirtualMachine) DeployVM(ctx context.Context, opts *cloudprovider.SInstanceDeployOptions) error {
  245. return cloudprovider.ErrNotImplemented
  246. }
  247. func (svm *SVirtualMachine) RebuildRoot(ctx context.Context, desc *cloudprovider.SManagedVMRebuildRootConfig) (string, error) {
  248. return "", cloudprovider.ErrNotImplemented
  249. }
  250. func (svm *SVirtualMachine) DoRebuildRoot(ctx context.Context, imagePath string, uuid string, uefi bool) error {
  251. if len(svm.vdisks) == 0 {
  252. return errors.Wrapf(errors.ErrNotFound, "empty vdisks")
  253. }
  254. return svm.rebuildDisk(ctx, &svm.vdisks[0], imagePath, uefi)
  255. }
  256. func (svm *SVirtualMachine) rebuildDisk(ctx context.Context, disk *SVirtualDisk, imagePath string, uefi bool) error {
  257. uuid := disk.GetId()
  258. sizeMb := disk.GetDiskSizeMB()
  259. diskKey := disk.getKey()
  260. ctlKey := disk.getControllerKey()
  261. unitNumber := *disk.dev.GetVirtualDevice().UnitNumber
  262. err := svm.doDetachAndDeleteDisk(ctx, disk)
  263. if err != nil {
  264. return err
  265. }
  266. err = svm.createDiskInternal(ctx, SDiskConfig{
  267. Uefi: uefi,
  268. SizeMb: int64(sizeMb),
  269. Uuid: uuid,
  270. ControllerKey: ctlKey,
  271. UnitNumber: unitNumber,
  272. Key: diskKey,
  273. ImagePath: imagePath,
  274. IsRoot: len(imagePath) > 0,
  275. }, false)
  276. if err != nil {
  277. return errors.Wrapf(err, "createDiskInternal")
  278. }
  279. for i := 1; i < len(svm.vdisks); i++ {
  280. err = svm.doDetachDisk(ctx, &svm.vdisks[i], false)
  281. if err != nil {
  282. return errors.Wrapf(err, "doDetachDisk %d", i)
  283. }
  284. err = svm.doAttachDisk(ctx, &svm.vdisks[i])
  285. if err != nil {
  286. return errors.Wrapf(err, "doAttachDisk: %d", i)
  287. }
  288. }
  289. return nil
  290. }
  291. func (svm *SVirtualMachine) UpdateVM(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error {
  292. err := svm.SetConfig(ctx, input)
  293. if err != nil {
  294. return errors.Wrap(err, "set description")
  295. }
  296. return nil
  297. }
  298. // TODO: detach disk to a separate directory, so as to keep disk independent of VM
  299. func (svm *SVirtualMachine) DetachDisk(ctx context.Context, diskId string) error {
  300. vdisk, err := svm.GetIDiskById(diskId)
  301. if err != nil {
  302. return err
  303. }
  304. return svm.doDetachDisk(ctx, vdisk.(*SVirtualDisk), false)
  305. }
  306. func (svm *SVirtualMachine) AttachDisk(ctx context.Context, diskId string) error {
  307. return cloudprovider.ErrNotImplemented
  308. }
  309. func (svm *SVirtualMachine) getUuid() string {
  310. return svm.getVirtualMachine().Summary.Config.Uuid
  311. }
  312. func (svm *SVirtualMachine) GetIHost() cloudprovider.ICloudHost {
  313. if svm.ihost == nil {
  314. svm.ihost = svm.getIHost()
  315. }
  316. return svm.ihost
  317. }
  318. func (svm *SVirtualMachine) getIHost() cloudprovider.ICloudHost {
  319. vm := svm.getVmObj()
  320. hostsys, err := vm.HostSystem(svm.manager.context)
  321. if err != nil {
  322. log.Errorf("fail to find host system for vm %s", err)
  323. return nil
  324. }
  325. ihost, err := svm.manager.FindHostByMoId(moRefId(hostsys.Reference()))
  326. if err != nil {
  327. log.Errorf("fail to find host %s for vm %s???", hostsys.Name(), svm.GetName())
  328. return nil
  329. }
  330. return ihost
  331. }
  332. func (svm *SVirtualMachine) GetIDisks() ([]cloudprovider.ICloudDisk, error) {
  333. idisks := make([]cloudprovider.ICloudDisk, len(svm.vdisks))
  334. for i := 0; i < len(svm.vdisks); i += 1 {
  335. idisks[i] = &(svm.vdisks[i])
  336. }
  337. return idisks, nil
  338. }
  339. func (svm *SVirtualMachine) GetIDiskById(idStr string) (cloudprovider.ICloudDisk, error) {
  340. for i := 0; i < len(svm.vdisks); i += 1 {
  341. if svm.vdisks[i].MatchId(idStr) {
  342. return &svm.vdisks[i], nil
  343. }
  344. }
  345. return nil, cloudprovider.ErrNotFound
  346. }
  347. func (svm *SVirtualMachine) GetINics() ([]cloudprovider.ICloudNic, error) {
  348. inics := make([]cloudprovider.ICloudNic, len(svm.vnics))
  349. for i := 0; i < len(svm.vnics); i += 1 {
  350. inics[i] = &(svm.vnics[i])
  351. }
  352. return inics, nil
  353. }
  354. func (svm *SVirtualMachine) GetIEIP() (cloudprovider.ICloudEIP, error) {
  355. return nil, nil
  356. }
  357. func (svm *SVirtualMachine) GetCpuSockets() int {
  358. vm := svm.getVirtualMachine()
  359. if vm.Config != nil {
  360. return int(svm.GetVcpuCount() / int(vm.Config.Hardware.NumCoresPerSocket))
  361. }
  362. return 1
  363. }
  364. func (svm *SVirtualMachine) GetVcpuCount() int {
  365. return int(svm.getVirtualMachine().Summary.Config.NumCpu)
  366. }
  367. func (svm *SVirtualMachine) GetVmemSizeMB() int {
  368. return int(svm.getVirtualMachine().Summary.Config.MemorySizeMB)
  369. }
  370. func (svm *SVirtualMachine) GetBootOrder() string {
  371. return "cdn"
  372. }
  373. func (svm *SVirtualMachine) GetVga() string {
  374. return "vga"
  375. }
  376. func (svm *SVirtualMachine) GetVdi() string {
  377. return "vmrc"
  378. }
  379. func (svm *SVirtualMachine) GetGuestFamily() string {
  380. moVM := svm.getVirtualMachine()
  381. return moVM.Config.AlternateGuestName
  382. }
  383. func (svm *SVirtualMachine) GetGuestId() string {
  384. moVM := svm.getVirtualMachine()
  385. return moVM.Config.GuestId
  386. }
  387. func (svm *SVirtualMachine) GetGuestFullName() string {
  388. moVM := svm.getVirtualMachine()
  389. return moVM.Config.GuestFullName
  390. }
  391. func (svm *SVirtualMachine) GetGuestState() string {
  392. moVM := svm.getVirtualMachine()
  393. return moVM.Guest.GuestState
  394. }
  395. func (svm *SVirtualMachine) GetGuestToolsStatus() string {
  396. moVM := svm.getVirtualMachine()
  397. return string(moVM.Guest.ToolsStatus)
  398. }
  399. func (svm *SVirtualMachine) isToolsOk() bool {
  400. switch svm.getVirtualMachine().Guest.ToolsStatus {
  401. case types.VirtualMachineToolsStatusToolsNotInstalled:
  402. return false
  403. case types.VirtualMachineToolsStatusToolsNotRunning:
  404. return false
  405. }
  406. return true
  407. }
  408. func (svm *SVirtualMachine) GetGuestToolsRunningStatus() string {
  409. moVM := svm.getVirtualMachine()
  410. return string(moVM.Guest.ToolsRunningStatus)
  411. }
  412. func (vm *SVirtualMachine) getNormalizedOsInfo() *imagetools.ImageInfo {
  413. if vm.osInfo == nil {
  414. if osInfo, ok := GuestOsInfo[vm.GetGuestId()]; ok {
  415. osInfo := imagetools.NormalizeImageInfo("", string(osInfo.OsArch), string(osInfo.OsType), osInfo.OsDistribution, osInfo.OsVersion)
  416. vm.osInfo = &osInfo
  417. } else {
  418. osInfo := imagetools.NormalizeImageInfo(vm.GetName(), "", "", "", "")
  419. vm.osInfo = &osInfo
  420. }
  421. }
  422. return vm.osInfo
  423. }
  424. func (vm *SVirtualMachine) GetOsType() cloudprovider.TOsType {
  425. return cloudprovider.TOsType(vm.getNormalizedOsInfo().OsType)
  426. }
  427. func (vm *SVirtualMachine) GetFullOsName() string {
  428. return vm.getNormalizedOsInfo().GetFullOsName()
  429. }
  430. func (vm *SVirtualMachine) GetOsDist() string {
  431. return vm.getNormalizedOsInfo().OsDistro
  432. }
  433. func (vm *SVirtualMachine) GetOsVersion() string {
  434. return vm.getNormalizedOsInfo().OsVersion
  435. }
  436. func (vm *SVirtualMachine) GetOsLang() string {
  437. return vm.getNormalizedOsInfo().OsLang
  438. }
  439. func (vm *SVirtualMachine) GetOsArch() string {
  440. return vm.getNormalizedOsInfo().OsArch
  441. }
  442. func (vm *SVirtualMachine) GetBios() cloudprovider.TBiosType {
  443. return cloudprovider.ToBiosType(vm.getBios())
  444. }
  445. func (vm *SVirtualMachine) getBios() string {
  446. // svm.obj.config.firmware
  447. switch vm.getVirtualMachine().Config.Firmware {
  448. case "efi":
  449. return "UEFI"
  450. case "bios":
  451. return "BIOS"
  452. default:
  453. return "BIOS"
  454. }
  455. }
  456. func (svm *SVirtualMachine) GetMachine() string {
  457. return "pc"
  458. }
  459. func (svm *SVirtualMachine) GetHypervisor() string {
  460. return api.HYPERVISOR_ESXI
  461. }
  462. func (svm *SVirtualMachine) getVmObj() *object.VirtualMachine {
  463. return object.NewVirtualMachine(svm.manager.client.Client, svm.getVirtualMachine().Self)
  464. }
  465. // ideopotent start
  466. func (svm *SVirtualMachine) StartVM(ctx context.Context) error {
  467. if svm.GetStatus() == api.VM_RUNNING {
  468. return nil
  469. }
  470. return svm.startVM(ctx)
  471. }
  472. func (svm *SVirtualMachine) startVM(ctx context.Context) error {
  473. ihost := svm.GetIHost()
  474. if ihost == nil {
  475. return errors.Wrap(cloudprovider.ErrInvalidStatus, "no valid host")
  476. }
  477. err := svm.makeNicsStartConnected(ctx)
  478. if err != nil {
  479. return errors.Wrapf(err, "makeNicStartConnected")
  480. }
  481. vm := svm.getVmObj()
  482. task, err := vm.PowerOn(ctx)
  483. if err != nil {
  484. return errors.Wrapf(err, "PowerOn")
  485. }
  486. err = task.Wait(ctx)
  487. if err != nil {
  488. return errors.Wrapf(err, "task.Wait")
  489. }
  490. return nil
  491. }
  492. func (svm *SVirtualMachine) makeNicsStartConnected(ctx context.Context) error {
  493. spec := types.VirtualMachineConfigSpec{}
  494. spec.CpuHotAddEnabled = &True
  495. spec.CpuHotRemoveEnabled = &True
  496. spec.MemoryHotAddEnabled = &True
  497. spec.DeviceChange = make([]types.BaseVirtualDeviceConfigSpec, len(svm.vnics))
  498. for i := 0; i < len(svm.vnics); i += 1 {
  499. spec.DeviceChange[i] = makeNicStartConnected(&svm.vnics[i])
  500. }
  501. vm := svm.getVmObj()
  502. task, err := vm.Reconfigure(ctx, spec)
  503. if err != nil {
  504. return err
  505. }
  506. return task.Wait(ctx)
  507. }
  508. func makeNicStartConnected(nic *SVirtualNIC) *types.VirtualDeviceConfigSpec {
  509. editSpec := types.VirtualDeviceConfigSpec{}
  510. editSpec.Operation = types.VirtualDeviceConfigSpecOperationEdit
  511. editSpec.FileOperation = ""
  512. editSpec.Device = nic.dev
  513. editSpec.Device.GetVirtualDevice().Connectable.StartConnected = true
  514. return &editSpec
  515. }
  516. func (svm *SVirtualMachine) StopVM(ctx context.Context, opts *cloudprovider.ServerStopOptions) error {
  517. if svm.GetStatus() == api.VM_READY {
  518. return nil
  519. }
  520. if !opts.IsForce && svm.isToolsOk() {
  521. return svm.shutdownVM(ctx)
  522. } else {
  523. return svm.poweroffVM(ctx)
  524. }
  525. }
  526. func (svm *SVirtualMachine) SuspendVM(ctx context.Context) error {
  527. vm := svm.getVmObj()
  528. task, err := vm.Suspend(ctx)
  529. if err != nil {
  530. return err
  531. }
  532. return task.Wait(ctx)
  533. }
  534. func (svm *SVirtualMachine) ResumeVM(ctx context.Context) error {
  535. if svm.GetStatus() == api.VM_RUNNING {
  536. return nil
  537. }
  538. vm := svm.getVmObj()
  539. task, err := vm.PowerOn(ctx)
  540. if err != nil {
  541. return errors.Wrap(err, "VM.PowerOn")
  542. }
  543. err = task.Wait(ctx)
  544. if err != nil {
  545. return errors.Wrap(err, "Task.Wait after VM.PowerOn")
  546. }
  547. return nil
  548. }
  549. func (svm *SVirtualMachine) poweroffVM(ctx context.Context) error {
  550. vm := svm.getVmObj()
  551. task, err := vm.PowerOff(ctx)
  552. if err != nil {
  553. return err
  554. }
  555. return task.Wait(ctx)
  556. }
  557. func (svm *SVirtualMachine) shutdownVM(ctx context.Context) error {
  558. vm := svm.getVmObj()
  559. err := vm.ShutdownGuest(ctx)
  560. if err != nil {
  561. return err
  562. }
  563. return err
  564. }
  565. func (svm *SVirtualMachine) doDestroy(ctx context.Context) error {
  566. vm := svm.getVmObj()
  567. task, err := vm.Destroy(ctx)
  568. if err != nil {
  569. return errors.Wrap(err, "unable to destroy vm")
  570. }
  571. return task.Wait(ctx)
  572. }
  573. func (svm *SVirtualMachine) doDelete(ctx context.Context) error {
  574. // detach all disks first
  575. for i := range svm.vdisks {
  576. err := svm.doDetachAndDeleteDisk(ctx, &svm.vdisks[i])
  577. if err != nil {
  578. return errors.Wrap(err, "doDetachAndDeteteDisk")
  579. }
  580. }
  581. return svm.doDestroy(ctx)
  582. }
  583. func (svm *SVirtualMachine) doUnregister(ctx context.Context) error {
  584. vm := svm.getVmObj()
  585. err := vm.Unregister(ctx)
  586. if err != nil {
  587. return errors.Wrapf(err, "Unregister")
  588. }
  589. return nil
  590. }
  591. func (svm *SVirtualMachine) DeleteVM(ctx context.Context) error {
  592. err := svm.doDestroy(ctx)
  593. if err != nil {
  594. return svm.doUnregister(ctx)
  595. }
  596. return nil
  597. }
  598. func (svm *SVirtualMachine) doDetachAndDeleteDisk(ctx context.Context, vdisk *SVirtualDisk) error {
  599. return svm.doDetachDisk(ctx, vdisk, true)
  600. }
  601. func (svm *SVirtualMachine) doDetachDisk(ctx context.Context, vdisk *SVirtualDisk, remove bool) error {
  602. removeSpec := types.VirtualDeviceConfigSpec{}
  603. removeSpec.Operation = types.VirtualDeviceConfigSpecOperationRemove
  604. removeSpec.Device = vdisk.dev
  605. spec := types.VirtualMachineConfigSpec{}
  606. spec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{&removeSpec}
  607. vm := svm.getVmObj()
  608. task, err := vm.Reconfigure(ctx, spec)
  609. if err != nil {
  610. return errors.Wrapf(err, "Reconfigure remove disk %s", vdisk.GetName())
  611. }
  612. err = task.Wait(ctx)
  613. if err != nil {
  614. return errors.Wrapf(err, "wait remove disk %s task", vdisk.GetName())
  615. }
  616. if !remove {
  617. return nil
  618. }
  619. return vdisk.Delete(ctx)
  620. }
  621. func (svm *SVirtualMachine) doAttachDisk(ctx context.Context, vdisk *SVirtualDisk) error {
  622. addSpec := types.VirtualDeviceConfigSpec{}
  623. addSpec.Operation = types.VirtualDeviceConfigSpecOperationAdd
  624. addSpec.Device = vdisk.dev
  625. spec := types.VirtualMachineConfigSpec{}
  626. spec.DeviceChange = []types.BaseVirtualDeviceConfigSpec{&addSpec}
  627. vm := svm.getVmObj()
  628. task, err := vm.Reconfigure(ctx, spec)
  629. if err != nil {
  630. return errors.Wrapf(err, "Reconfigure add disk %s", vdisk.GetName())
  631. }
  632. err = task.Wait(ctx)
  633. if err != nil {
  634. return errors.Wrapf(err, "wait remove add %s task", vdisk.GetName())
  635. }
  636. return nil
  637. }
  638. func (svm *SVirtualMachine) GetVNCInfo(input *cloudprovider.ServerVncInput) (*cloudprovider.ServerVncOutput, error) {
  639. hostVer := svm.GetIHost().GetVersion()
  640. if version.GE(hostVer, "6.5") {
  641. info, err := svm.acquireWebmksTicket("webmks")
  642. if err == nil {
  643. return info, nil
  644. }
  645. }
  646. return svm.acquireVmrcUrl()
  647. }
  648. func (svm *SVirtualMachine) GetVmrcInfo() (*cloudprovider.ServerVncOutput, error) {
  649. return svm.acquireVmrcUrl()
  650. }
  651. func (svm *SVirtualMachine) GetWebmksInfo() (*cloudprovider.ServerVncOutput, error) {
  652. return svm.acquireWebmksTicket("webmks")
  653. }
  654. func (svm *SVirtualMachine) acquireWebmksTicket(ticketType string) (*cloudprovider.ServerVncOutput, error) {
  655. vm := object.NewVirtualMachine(svm.manager.client.Client, svm.getVirtualMachine().Self)
  656. ticket, err := vm.AcquireTicket(svm.manager.context, ticketType)
  657. if err != nil {
  658. return nil, err
  659. }
  660. host := ticket.Host
  661. if len(host) == 0 {
  662. host = svm.manager.host
  663. }
  664. port := ticket.Port
  665. if port == 0 {
  666. port = int32(svm.manager.port)
  667. }
  668. if port == 0 {
  669. port = 443
  670. }
  671. ret := &cloudprovider.ServerVncOutput{
  672. Url: fmt.Sprintf("wss://%s:%d/ticket/%s", host, port, ticket.Ticket),
  673. Protocol: "wmks",
  674. Hypervisor: api.HYPERVISOR_ESXI,
  675. }
  676. return ret, nil
  677. }
  678. func (svm *SVirtualMachine) acquireVmrcUrl() (*cloudprovider.ServerVncOutput, error) {
  679. ticket, err := svm.manager.acquireCloneTicket()
  680. if err != nil {
  681. return nil, err
  682. }
  683. port := svm.manager.port
  684. if port == 0 {
  685. port = 443
  686. }
  687. ret := &cloudprovider.ServerVncOutput{
  688. Url: fmt.Sprintf("vmrc://clone:%s@%s:%d/?moid=%s", ticket, svm.manager.host, port, svm.GetId()),
  689. Protocol: "vmrc",
  690. }
  691. return ret, nil
  692. }
  693. func (svm *SVirtualMachine) ChangeConfig(ctx context.Context, config *cloudprovider.SManagedVMChangeConfig) error {
  694. return svm.doChangeConfig(ctx, int32(config.Cpu), int32(config.CpuSocket), int64(config.MemoryMB), "", "")
  695. }
  696. func (svm *SVirtualMachine) GetVersion() string {
  697. return svm.getVirtualMachine().Config.Version
  698. }
  699. func (svm *SVirtualMachine) doChangeConfig(ctx context.Context, ncpu, cpuSockets int32, vmemMB int64, guestId string, version string) error {
  700. changed := false
  701. configSpec := types.VirtualMachineConfigSpec{}
  702. cpu := svm.GetVcpuCount()
  703. if int(ncpu) != svm.GetVcpuCount() {
  704. configSpec.NumCPUs = ncpu
  705. cpu = int(ncpu)
  706. changed = true
  707. }
  708. if cpuSockets > 0 && int(cpuSockets) != svm.GetCpuSockets() {
  709. configSpec.NumCoresPerSocket = int32(cpu / int(cpuSockets))
  710. changed = true
  711. }
  712. if int(vmemMB) != svm.GetVmemSizeMB() {
  713. configSpec.MemoryMB = vmemMB
  714. changed = true
  715. }
  716. if len(guestId) > 0 && guestId != svm.GetGuestId() {
  717. configSpec.GuestId = guestId
  718. changed = true
  719. }
  720. if len(version) > 0 && version != svm.GetVersion() {
  721. configSpec.Version = version
  722. changed = true
  723. }
  724. if !changed {
  725. return nil
  726. }
  727. vm := svm.getVmObj()
  728. task, err := vm.Reconfigure(ctx, configSpec)
  729. if err != nil {
  730. return err
  731. }
  732. err = task.Wait(ctx)
  733. if err != nil {
  734. return err
  735. }
  736. return svm.Refresh()
  737. }
  738. func (svm *SVirtualMachine) SetSecurityGroups(secgroupIds []string) error {
  739. return cloudprovider.ErrNotImplemented
  740. }
  741. func (svm *SVirtualMachine) GetBillingType() string {
  742. return billing_api.BILLING_TYPE_POSTPAID
  743. }
  744. func (svm *SVirtualMachine) GetCreatedAt() time.Time {
  745. moVM := svm.getVirtualMachine()
  746. ctm := moVM.Config.CreateDate
  747. if ctm != nil {
  748. return *ctm
  749. } else {
  750. return time.Time{}
  751. }
  752. }
  753. func (svm *SVirtualMachine) SetConfig(ctx context.Context, input cloudprovider.SInstanceUpdateOptions) error {
  754. setDescTask, err := svm.getVmObj().Reconfigure(ctx, types.VirtualMachineConfigSpec{
  755. Name: input.NAME,
  756. Annotation: input.Description,
  757. })
  758. if err != nil {
  759. return errors.Wrap(err, "set task")
  760. }
  761. return setDescTask.Wait(ctx)
  762. }
  763. func (svm *SVirtualMachine) GetExpiredAt() time.Time {
  764. return time.Time{}
  765. }
  766. func (svm *SVirtualMachine) UpdateUserData(userData string) error {
  767. return nil
  768. }
  769. func (svm *SVirtualMachine) fetchHardwareInfo() error {
  770. svm.vnics = make([]SVirtualNIC, 0)
  771. svm.vdisks = make([]SVirtualDisk, 0)
  772. svm.cdroms = make([]SVirtualCdrom, 0)
  773. svm.devs = make(map[int32]SVirtualDevice)
  774. moVM := svm.getVirtualMachine()
  775. // MAX_TRIES := 3
  776. // for tried := 0; tried < MAX_TRIES && (moVM == nil || moVM.Config == nil || moVM.Config.Hardware.Device == nil); tried += 1 {
  777. // time.Sleep(time.Second)
  778. // }
  779. if moVM == nil || moVM.Config == nil || moVM.Config.Hardware.Device == nil {
  780. return fmt.Errorf("invalid vm")
  781. }
  782. // sort devices via their Key
  783. devices := moVM.Config.Hardware.Device
  784. sort.Slice(devices, func(i, j int) bool {
  785. return devices[i].GetVirtualDevice().Key < devices[j].GetVirtualDevice().Key
  786. })
  787. for i := 0; i < len(devices); i += 1 {
  788. dev := devices[i]
  789. devType := reflect.Indirect(reflect.ValueOf(dev)).Type()
  790. etherType := reflect.TypeOf((*types.VirtualEthernetCard)(nil)).Elem()
  791. diskType := reflect.TypeOf((*types.VirtualDisk)(nil)).Elem()
  792. vgaType := reflect.TypeOf((*types.VirtualMachineVideoCard)(nil)).Elem()
  793. cdromType := reflect.TypeOf((*types.VirtualCdrom)(nil)).Elem()
  794. if reflectutils.StructContains(devType, etherType) {
  795. vnic := NewVirtualNIC(svm, dev, len(svm.vnics))
  796. svm.vnics = append(svm.vnics, vnic)
  797. } else if reflectutils.StructContains(devType, diskType) {
  798. svm.vdisks = append(svm.vdisks, NewVirtualDisk(svm, dev, len(svm.vdisks)))
  799. } else if reflectutils.StructContains(devType, vgaType) {
  800. svm.vga = NewVirtualVGA(svm, dev, 0)
  801. } else if reflectutils.StructContains(devType, cdromType) {
  802. svm.cdroms = append(svm.cdroms, NewVirtualCdrom(svm, dev, len(svm.cdroms)))
  803. }
  804. vdev := NewVirtualDevice(svm, dev, 0)
  805. svm.devs[vdev.getKey()] = vdev
  806. }
  807. svm.rigorous()
  808. for i := range svm.vdisks {
  809. if svm.vdisks[i].GetDiskType() == api.DISK_TYPE_SYS {
  810. svm.vdisks[i], svm.vdisks[0] = svm.vdisks[0], svm.vdisks[i]
  811. break
  812. }
  813. }
  814. return nil
  815. }
  816. func (svm *SVirtualMachine) rigorous() {
  817. hasRoot := false
  818. for i := range svm.vdisks {
  819. if svm.vdisks[i].IsRoot {
  820. hasRoot = true
  821. break
  822. }
  823. }
  824. if !hasRoot && len(svm.vdisks) > 0 {
  825. svm.vdisks[0].IsRoot = true
  826. }
  827. }
  828. func (svm *SVirtualMachine) getVdev(key int32) SVirtualDevice {
  829. return svm.devs[key]
  830. }
  831. func (svm *SVirtualMachine) getNetTags() string {
  832. info := make([]string, 0)
  833. for _, nicConf := range svm.getGuestIps() {
  834. info = append(info, nicConf.Mac, nicConf.Network)
  835. info = append(info, nicConf.IPs...)
  836. }
  837. return strings.Join(info, "/")
  838. }
  839. type sNicConfig struct {
  840. Mac string
  841. Network string
  842. IPs []string
  843. }
  844. func (svm *SVirtualMachine) fetchGuestIps() map[string]sNicConfig {
  845. guestIps := make(map[string]sNicConfig)
  846. moVM := svm.getVirtualMachine()
  847. for _, net := range moVM.Guest.Net {
  848. if len(net.Network) == 0 {
  849. continue
  850. }
  851. nicConf := sNicConfig{}
  852. nicConf.Mac = netutils.FormatMacAddr(net.MacAddress)
  853. nicConf.Network = net.Network
  854. for _, ip := range net.IpAddress {
  855. if regutils.MatchIP4Addr(ip) && !strings.HasPrefix(ip, "169.254.") {
  856. if !vmIPV4Filter.Contains(ip) {
  857. continue
  858. }
  859. nicConf.IPs = append(nicConf.IPs, ip)
  860. }
  861. }
  862. guestIps[nicConf.Mac] = nicConf
  863. }
  864. return guestIps
  865. }
  866. func (svm *SVirtualMachine) getGuestIps() map[string]sNicConfig {
  867. if svm.guestIps == nil {
  868. svm.guestIps = svm.fetchGuestIps()
  869. }
  870. return svm.guestIps
  871. }
  872. func (svm *SVirtualMachine) GetIps() []string {
  873. iplists := make([]string, 0)
  874. for _, nicConf := range svm.getGuestIps() {
  875. iplists = append(iplists, nicConf.IPs...)
  876. }
  877. return iplists
  878. }
  879. func (svm *SVirtualMachine) GetVGADevice() string {
  880. return svm.vga.String()
  881. }
  882. var (
  883. driverTable = map[string][]string{
  884. "sata": {"ahci"},
  885. "scsi": {"parascsi", "lsilogic", "lsilogicsas", "buslogic"},
  886. "pvscsi": {"parascsi"},
  887. "ide": {"ide"},
  888. }
  889. )
  890. func (svm *SVirtualMachine) getDevsByDriver(driver string) []SVirtualDevice {
  891. devs := make([]SVirtualDevice, 0)
  892. for _, drv := range svm.devs {
  893. if strings.HasSuffix(drv.GetDriver(), fmt.Sprintf("%scontroller", driver)) {
  894. devs = append(devs, drv)
  895. }
  896. }
  897. return devs
  898. }
  899. func minDevKey(devs []SVirtualDevice) int32 {
  900. var minKey int32 = -1
  901. for i := 0; i < len(devs); i += 1 {
  902. if minKey < 0 || minKey > devs[i].getKey() {
  903. minKey = devs[i].getKey()
  904. }
  905. }
  906. return minKey
  907. }
  908. func minDiskKey(devs []SVirtualDisk) int32 {
  909. var minKey int32 = -1
  910. for i := 0; i < len(devs); i += 1 {
  911. if minKey < 0 || minKey > devs[i].getKey() {
  912. minKey = devs[i].getKey()
  913. }
  914. }
  915. return minKey
  916. }
  917. func (svm *SVirtualMachine) FindController(ctx context.Context, driver string) ([]SVirtualDevice, error) {
  918. aliasDrivers, ok := driverTable[driver]
  919. if !ok {
  920. return nil, errors.Wrapf(errors.ErrNotFound, "Unsupported disk driver %s", driver)
  921. }
  922. var devs []SVirtualDevice
  923. for _, alias := range aliasDrivers {
  924. devs = svm.getDevsByDriver(alias)
  925. if len(devs) > 0 {
  926. break
  927. }
  928. }
  929. return devs, nil
  930. }
  931. func (svm *SVirtualMachine) FindDiskByDriver(drivers ...string) []SVirtualDisk {
  932. disks := make([]SVirtualDisk, 0)
  933. for i := range svm.vdisks {
  934. if utils.IsInStringArray(svm.vdisks[i].GetDriver(), drivers) {
  935. disks = append(disks, svm.vdisks[i])
  936. }
  937. }
  938. return disks
  939. }
  940. func (svm *SVirtualMachine) devNumWithCtrlKey(ctrlKey int32) int {
  941. n := 0
  942. for _, dev := range svm.devs {
  943. if dev.getControllerKey() == ctrlKey {
  944. n++
  945. }
  946. }
  947. return n
  948. }
  949. func (svm *SVirtualMachine) getLayoutEx() *types.VirtualMachineFileLayoutEx {
  950. vm := svm.getVirtualMachine()
  951. if vm.LayoutEx != nil {
  952. return vm.LayoutEx
  953. }
  954. var nvm mo.VirtualMachine
  955. err := svm.manager.reference2Object(vm.Self, vmLayoutExProps, &nvm)
  956. if err != nil {
  957. log.Errorf("unable to fetch LayoutEx.File from vc: %v", err)
  958. }
  959. vm.LayoutEx = nvm.LayoutEx
  960. return vm.LayoutEx
  961. }
  962. func (svm *SVirtualMachine) CreateDisk(ctx context.Context, opts *cloudprovider.GuestDiskCreateOptions) (string, error) {
  963. if opts.Driver == "pvscsi" {
  964. opts.Driver = "scsi"
  965. }
  966. var ds *SDatastore
  967. var err error
  968. if opts.StorageId != "" {
  969. ihost := svm.getIHost()
  970. if ihost == nil {
  971. return "", fmt.Errorf("unable to get host of virtualmachine %s", svm.GetName())
  972. }
  973. ds, err = ihost.(*SHost).FindDataStoreById(opts.StorageId)
  974. if err != nil {
  975. return "", errors.Wrapf(err, "unable to find datastore %s", opts.StorageId)
  976. }
  977. }
  978. devs, err := svm.FindController(ctx, opts.Driver)
  979. if err != nil {
  980. return "", err
  981. }
  982. if len(devs) == 0 {
  983. return "", svm.createDriverAndDisk(ctx, ds, opts.SizeMb, opts.UUID, opts.Driver, opts.Preallocation)
  984. }
  985. numDevBelowCtrl := make([]int, len(devs))
  986. for i := range numDevBelowCtrl {
  987. numDevBelowCtrl[i] = svm.devNumWithCtrlKey(devs[i].getKey())
  988. }
  989. // find the min one
  990. ctrlKey := devs[0].getKey()
  991. unitNumber := numDevBelowCtrl[0]
  992. for i := 1; i < len(numDevBelowCtrl); i++ {
  993. if numDevBelowCtrl[i] >= unitNumber {
  994. continue
  995. }
  996. ctrlKey = devs[i].getKey()
  997. unitNumber = numDevBelowCtrl[i]
  998. }
  999. diskKey := svm.FindMinDiffKey(2000)
  1000. // By default, the virtual SCSI controller is assigned to virtual device node (z:7),
  1001. // so that device node is unavailable for hard disks or other devices.
  1002. if unitNumber >= 7 && opts.Driver == "scsi" {
  1003. unitNumber++
  1004. }
  1005. return "", svm.createDiskInternal(ctx, SDiskConfig{
  1006. SizeMb: int64(opts.SizeMb),
  1007. Uuid: opts.UUID,
  1008. UnitNumber: int32(unitNumber),
  1009. ControllerKey: ctrlKey,
  1010. Key: diskKey,
  1011. Datastore: ds,
  1012. Preallocation: opts.Preallocation,
  1013. }, true)
  1014. }
  1015. // createDriverAndDisk will create a driver and disk associated with the driver
  1016. func (svm *SVirtualMachine) createDriverAndDisk(ctx context.Context, ds *SDatastore, sizeMb int, uuid string, driver, preallocation string) error {
  1017. if driver != "scsi" && driver != "pvscsi" {
  1018. return fmt.Errorf("Driver %s is not supported", driver)
  1019. }
  1020. deviceChange := make([]types.BaseVirtualDeviceConfigSpec, 0, 2)
  1021. // find a suitable key for scsi or pvscsi driver
  1022. scsiKey := svm.FindMinDiffKey(1000)
  1023. deviceChange = append(deviceChange, addDevSpec(NewSCSIDev(scsiKey, 100, driver)))
  1024. // find a suitable key for disk
  1025. diskKey := svm.FindMinDiffKey(2000)
  1026. if diskKey == scsiKey {
  1027. // unarrivelable
  1028. log.Errorf("there is no suitable key between 1000 and 2000???!")
  1029. }
  1030. return svm.createDiskWithDeviceChange(ctx, deviceChange,
  1031. SDiskConfig{
  1032. SizeMb: int64(sizeMb),
  1033. Uuid: uuid,
  1034. ControllerKey: scsiKey,
  1035. UnitNumber: 0,
  1036. Key: scsiKey,
  1037. ImagePath: "",
  1038. IsRoot: false,
  1039. Datastore: ds,
  1040. Preallocation: preallocation,
  1041. }, true)
  1042. }
  1043. func (svm *SVirtualMachine) getDatastoreAndRootImagePath(suffixCheck bool) (string, *SDatastore, error) {
  1044. layoutEx := svm.getLayoutEx()
  1045. if layoutEx == nil || len(layoutEx.File) == 0 {
  1046. return "", nil, fmt.Errorf("invalid LayoutEx")
  1047. }
  1048. for _, f := range layoutEx.File {
  1049. if suffixCheck && !strings.HasSuffix(f.Name, ".vmdk") {
  1050. continue
  1051. }
  1052. file := f.Name
  1053. // find stroage
  1054. host := svm.GetIHost()
  1055. storages, err := host.GetIStorages()
  1056. if err != nil {
  1057. return "", nil, errors.Wrap(err, "host.GetIStorages")
  1058. }
  1059. var datastore *SDatastore
  1060. for i := range storages {
  1061. ds := storages[i].(*SDatastore)
  1062. if ds.HasFile(file) {
  1063. datastore = ds
  1064. break
  1065. }
  1066. }
  1067. if datastore == nil {
  1068. return "", nil, fmt.Errorf("can't find storage associated with vm %q", svm.GetName())
  1069. }
  1070. if strings.HasSuffix(f.Name, ".vmdk") {
  1071. return datastore.getPathString(datastore.cleanPath(file)), datastore, nil
  1072. }
  1073. path := datastore.cleanPath(file)
  1074. vmDir := strings.Split(path, "/")[0]
  1075. return datastore.getPathString(fmt.Sprintf("%s/%s.vmdk", vmDir, vmDir)), datastore, nil
  1076. }
  1077. return "", nil, fmt.Errorf("can't find root image path")
  1078. }
  1079. func (svm *SVirtualMachine) GetRootImagePath() (string, error) {
  1080. path, _, err := svm.getDatastoreAndRootImagePath(true)
  1081. if err != nil {
  1082. return "", err
  1083. }
  1084. return path, nil
  1085. }
  1086. func (svm *SVirtualMachine) CopyRootDisk(ctx context.Context, imagePath string) (string, error) {
  1087. newImagePath, datastore, err := svm.getDatastoreAndRootImagePath(false)
  1088. if err != nil {
  1089. return "", errors.Wrapf(err, "GetRootImagePath")
  1090. }
  1091. ds, err := datastore.getDatastoreObj(ctx)
  1092. if err != nil {
  1093. return "", errors.Wrapf(err, "getDatastoreObj")
  1094. }
  1095. fm := ds.NewFileManager(datastore.datacenter.getObjectDatacenter(), true)
  1096. err = fm.Copy(ctx, imagePath, newImagePath)
  1097. if err != nil {
  1098. return "", errors.Wrapf(err, "unable to copy system disk %s -> %s", imagePath, newImagePath)
  1099. }
  1100. return newImagePath, nil
  1101. }
  1102. func (svm *SVirtualMachine) createDiskWithDeviceChange(ctx context.Context, deviceChange []types.BaseVirtualDeviceConfigSpec, config SDiskConfig, check bool) error {
  1103. var err error
  1104. // copy disk
  1105. if len(config.ImagePath) > 0 {
  1106. config.IsRoot = true
  1107. config.ImagePath, err = svm.CopyRootDisk(ctx, config.ImagePath)
  1108. if err != nil {
  1109. return errors.Wrap(err, "unable to copyRootDisk")
  1110. }
  1111. }
  1112. devSpec, err := NewDiskDev(ctx, int64(config.SizeMb), config)
  1113. if err != nil {
  1114. return errors.Wrapf(err, "NewDiskDev")
  1115. }
  1116. spec := addDevSpec(devSpec)
  1117. if len(config.ImagePath) == 0 {
  1118. spec.FileOperation = types.VirtualDeviceConfigSpecFileOperationCreate
  1119. }
  1120. configSpec := types.VirtualMachineConfigSpec{}
  1121. configSpec.DeviceChange = append(deviceChange, spec)
  1122. if config.IsRoot {
  1123. configSpec.Firmware = "bios"
  1124. if config.Uefi {
  1125. configSpec.Firmware = "efi"
  1126. }
  1127. }
  1128. vmObj := svm.getVmObj()
  1129. task, err := vmObj.Reconfigure(ctx, configSpec)
  1130. if err != nil {
  1131. return errors.Wrap(err, "vmObj.Reconfigure")
  1132. }
  1133. err = task.Wait(ctx)
  1134. if err != nil {
  1135. return errors.Wrap(err, "task.Wait")
  1136. }
  1137. if !check {
  1138. return nil
  1139. }
  1140. oldDiskCnt := len(svm.vdisks)
  1141. maxTries := 60
  1142. for tried := 0; tried < maxTries; tried += 1 {
  1143. time.Sleep(time.Second)
  1144. svm.Refresh()
  1145. if len(svm.vdisks) > oldDiskCnt {
  1146. return nil
  1147. }
  1148. }
  1149. return cloudprovider.ErrTimeout
  1150. }
  1151. func (svm *SVirtualMachine) createDiskInternal(ctx context.Context, config SDiskConfig, check bool) error {
  1152. return svm.createDiskWithDeviceChange(ctx, nil, config, check)
  1153. }
  1154. func (svm *SVirtualMachine) Renew(bc billing.SBillingCycle) error {
  1155. return cloudprovider.ErrNotSupported
  1156. }
  1157. func (svm *SVirtualMachine) GetProjectId() string {
  1158. pool, err := svm.getResourcePool()
  1159. if err != nil {
  1160. return ""
  1161. }
  1162. if pool != nil {
  1163. return pool.GetId()
  1164. }
  1165. return ""
  1166. }
  1167. func (svm *SVirtualMachine) GetError() error {
  1168. return nil
  1169. }
  1170. func (svm *SVirtualMachine) getResourcePool() (*SResourcePool, error) {
  1171. vm := svm.getVirtualMachine()
  1172. morp := mo.ResourcePool{}
  1173. if vm.ResourcePool == nil {
  1174. return nil, errors.Error("nil resource pool")
  1175. }
  1176. err := svm.manager.reference2Object(*vm.ResourcePool, RESOURCEPOOL_PROPS, &morp)
  1177. if err != nil {
  1178. return nil, errors.Wrap(err, "svm.manager.reference2Object")
  1179. }
  1180. rp := NewResourcePool(svm.manager, &morp, svm.datacenter)
  1181. return rp, nil
  1182. }
  1183. func (svm *SVirtualMachine) CheckFileInfo(ctx context.Context) error {
  1184. layoutEx := svm.getLayoutEx()
  1185. if layoutEx != nil && len(layoutEx.File) > 0 {
  1186. file := layoutEx.File[0]
  1187. host := svm.GetIHost()
  1188. storages, err := host.GetIStorages()
  1189. if err != nil {
  1190. return errors.Wrap(err, "host.GetIStorages")
  1191. }
  1192. for i := range storages {
  1193. ds := storages[i].(*SDatastore)
  1194. if ds.HasFile(file.Name) {
  1195. _, err := ds.CheckFile(ctx, file.Name)
  1196. if err != nil {
  1197. return errors.Wrapf(err, "CheckFile %s", file.Name)
  1198. }
  1199. break
  1200. }
  1201. }
  1202. }
  1203. return nil
  1204. }
  1205. func (svm *SVirtualMachine) DoRename(ctx context.Context, name string) error {
  1206. task, err := svm.getVmObj().Rename(ctx, name)
  1207. if err != nil {
  1208. return errors.Wrap(err, "object.VirtualMachine.Rename")
  1209. }
  1210. return task.Wait(ctx)
  1211. }
  1212. func (svm *SVirtualMachine) GetMoid() string {
  1213. return svm.getVirtualMachine().Self.Value
  1214. }
  1215. func (svm *SVirtualMachine) GetToolsVersion() string {
  1216. return svm.getVirtualMachine().Guest.ToolsVersion
  1217. }
  1218. type SServerNic struct {
  1219. Name string `json:"name"`
  1220. Index int `json:"index"`
  1221. Bridge string `json:"bridge"`
  1222. Domain string `json:"domain"`
  1223. Ip string `json:"ip"`
  1224. Vlan int `json:"vlan"`
  1225. Driver string `json:"driver"`
  1226. Masklen int `json:"masklen"`
  1227. Virtual bool `json:"virtual"`
  1228. Manual bool `json:"manual"`
  1229. WireId string `json:"wire_id"`
  1230. NetId string `json:"net_id"`
  1231. Mac string `json:"mac"`
  1232. BandWidth int `json:"bw"`
  1233. Mtu int `json:"mtu,omitempty"`
  1234. Dns string `json:"dns"`
  1235. Ntp string `json:"ntp"`
  1236. Net string `json:"net"`
  1237. Interface string `json:"interface"`
  1238. Gateway string `json:"gateway"`
  1239. Ifname string `json:"ifname"`
  1240. NicType string `json:"nic_type,omitempty"`
  1241. LinkUp bool `json:"link_up,omitempty"`
  1242. TeamWith string `json:"team_with,omitempty"`
  1243. TeamingMaster *SServerNic `json:"-"`
  1244. TeamingSlaves []*SServerNic `json:"-"`
  1245. }
  1246. func (nicdesc SServerNic) getNicDns() []string {
  1247. dnslist := []string{}
  1248. if len(nicdesc.Dns) > 0 {
  1249. dnslist = append(dnslist, nicdesc.Dns)
  1250. }
  1251. return dnslist
  1252. }
  1253. func (svm *SVirtualMachine) DoCustomize(ctx context.Context, params jsonutils.JSONObject) error {
  1254. spec := new(types.CustomizationSpec)
  1255. ipSettings := new(types.CustomizationGlobalIPSettings)
  1256. domain := "local"
  1257. if params.Contains("domain") {
  1258. domain, _ = params.GetString("domain")
  1259. }
  1260. ipSettings.DnsSuffixList = []string{domain}
  1261. // deal nics
  1262. serverNics := make([]SServerNic, 0)
  1263. err := params.Unmarshal(&serverNics, "nics")
  1264. if err != nil {
  1265. return errors.Wrap(err, "Unmarshal nics")
  1266. }
  1267. // find dnsServerList
  1268. for i := range serverNics {
  1269. dnsList := serverNics[i].getNicDns()
  1270. if len(dnsList) != 0 {
  1271. ipSettings.DnsServerList = dnsList
  1272. }
  1273. }
  1274. spec.GlobalIPSettings = *ipSettings
  1275. maps := make([]types.CustomizationAdapterMapping, 0, len(serverNics))
  1276. for _, nic := range serverNics {
  1277. conf := types.CustomizationAdapterMapping{}
  1278. conf.MacAddress = nic.Mac
  1279. if len(conf.MacAddress) == 0 {
  1280. conf.MacAddress = "9e:46:27:21:a2:b2"
  1281. }
  1282. conf.Adapter = types.CustomizationIPSettings{}
  1283. fixedIp := new(types.CustomizationFixedIp)
  1284. fixedIp.IpAddress = nic.Ip
  1285. if len(fixedIp.IpAddress) == 0 {
  1286. fixedIp.IpAddress = "10.168.26.23"
  1287. }
  1288. conf.Adapter.Ip = fixedIp
  1289. maskLen := nic.Masklen
  1290. if maskLen == 0 {
  1291. maskLen = 24
  1292. }
  1293. mask := netutils.Netlen2Mask(maskLen)
  1294. conf.Adapter.SubnetMask = mask
  1295. if len(nic.Gateway) != 0 {
  1296. conf.Adapter.Gateway = []string{nic.Gateway}
  1297. }
  1298. dnsList := nic.getNicDns()
  1299. if len(dnsList) != 0 {
  1300. conf.Adapter.DnsServerList = dnsList
  1301. dns := nic.Domain
  1302. if len(dns) == 0 {
  1303. dns = "local"
  1304. }
  1305. conf.Adapter.DnsDomain = dns
  1306. }
  1307. maps = append(maps, conf)
  1308. }
  1309. spec.NicSettingMap = maps
  1310. var (
  1311. osName string
  1312. name = "yunionhost"
  1313. hostname = name
  1314. )
  1315. if params.Contains("os_name") {
  1316. osName, _ = params.GetString("os_name")
  1317. }
  1318. if params.Contains("name") {
  1319. name, _ = params.GetString("name")
  1320. hostname = name
  1321. }
  1322. if params.Contains("hostname") {
  1323. hostname, _ = params.GetString("hostname")
  1324. }
  1325. // avoid spec.identity.hostName error
  1326. hostname = func() string {
  1327. ret := ""
  1328. for _, s := range hostname {
  1329. if unicode.IsDigit(s) || unicode.IsLetter(s) || s == '-' {
  1330. ret += string(s)
  1331. }
  1332. }
  1333. return ret
  1334. }()
  1335. if osName == "Linux" {
  1336. linuxPrep := types.CustomizationLinuxPrep{
  1337. HostName: &types.CustomizationFixedName{Name: hostname},
  1338. Domain: domain,
  1339. TimeZone: "Asia/Shanghai",
  1340. }
  1341. spec.Identity = &linuxPrep
  1342. } else if osName == "Windows" {
  1343. if len(hostname) > 15 {
  1344. hostname = hostname[:15]
  1345. }
  1346. sysPrep := types.CustomizationSysprep{
  1347. GuiUnattended: types.CustomizationGuiUnattended{
  1348. TimeZone: 210,
  1349. AutoLogon: false,
  1350. },
  1351. UserData: types.CustomizationUserData{
  1352. FullName: "Administrator",
  1353. OrgName: "Yunion",
  1354. ProductId: "",
  1355. ComputerName: &types.CustomizationFixedName{
  1356. Name: hostname,
  1357. },
  1358. },
  1359. Identification: types.CustomizationIdentification{},
  1360. }
  1361. spec.Identity = &sysPrep
  1362. }
  1363. log.Infof("customize spec: %#v", spec)
  1364. task, err := svm.getVmObj().Customize(ctx, *spec)
  1365. if err != nil {
  1366. return errors.Wrap(err, "object.VirtualMachine.Customize")
  1367. }
  1368. return task.Wait(ctx)
  1369. }
  1370. func (svm *SVirtualMachine) ExportTemplate(ctx context.Context, idx int, diskPath string) error {
  1371. lease, err := svm.getVmObj().Export(ctx)
  1372. if err != nil {
  1373. return errors.Wrap(err, "esxi.SVirtualMachine.DoExportTemplate")
  1374. }
  1375. info, err := lease.Wait(ctx, nil)
  1376. if err != nil {
  1377. return errors.Wrap(err, "lease.Wait")
  1378. }
  1379. u := lease.StartUpdater(ctx, info)
  1380. defer u.Done()
  1381. if idx >= len(info.Items) {
  1382. return errors.Error(fmt.Sprintf("No such Device whose index is %d", idx))
  1383. }
  1384. lr := newLeaseLogger("download vmdk", 5)
  1385. lr.Log()
  1386. defer lr.End()
  1387. // filter vmdk item
  1388. vmdkItems := make([]nfc.FileItem, 0, len(info.Items)/2)
  1389. for i := range info.Items {
  1390. if strings.HasSuffix(info.Items[i].Path, ".vmdk") {
  1391. vmdkItems = append(vmdkItems, info.Items[i])
  1392. } else {
  1393. log.Infof("item.Path does not end in '.vmdk': %#v", info.Items[i])
  1394. }
  1395. }
  1396. log.Debugf("download to %s start...", diskPath)
  1397. err = lease.DownloadFile(ctx, diskPath, vmdkItems[idx], soap.Download{Progress: lr})
  1398. if err != nil {
  1399. return errors.Wrap(err, "lease.DownloadFile")
  1400. }
  1401. err = lease.Complete(ctx)
  1402. if err != nil {
  1403. return errors.Wrap(err, "lease.Complete")
  1404. }
  1405. log.Debugf("download to %s finish", diskPath)
  1406. return nil
  1407. }
  1408. func (svm *SVirtualMachine) GetSerialOutput(port int) (string, error) {
  1409. return "", cloudprovider.ErrNotImplemented
  1410. }
  1411. func (svm *SVirtualMachine) ConvertPublicIpToEip() error {
  1412. return cloudprovider.ErrNotSupported
  1413. }
  1414. func (svm *SVirtualMachine) IsAutoRenew() bool {
  1415. return false
  1416. }
  1417. func (svm *SVirtualMachine) SetAutoRenew(bc billing.SBillingCycle) error {
  1418. return cloudprovider.ErrNotSupported
  1419. }
  1420. func (svm *SVirtualMachine) FindMinDiffKey(limit int32) int32 {
  1421. if svm.devs == nil {
  1422. svm.fetchHardwareInfo()
  1423. }
  1424. devKeys := make([]int32, 0, len(svm.devs))
  1425. for key := range svm.devs {
  1426. devKeys = append(devKeys, key)
  1427. }
  1428. sort.Slice(devKeys, func(i int, j int) bool {
  1429. return devKeys[i] < devKeys[j]
  1430. })
  1431. for _, key := range devKeys {
  1432. switch {
  1433. case key < limit:
  1434. case key == limit:
  1435. limit += 1
  1436. case key > limit:
  1437. return limit
  1438. }
  1439. }
  1440. return limit
  1441. }
  1442. func (svm *SVirtualMachine) relocate(hostId string) error {
  1443. var targetHs *mo.HostSystem
  1444. if hostId == "" {
  1445. return errors.Wrap(fmt.Errorf("require hostId"), "relocate")
  1446. }
  1447. ihost, err := svm.manager.GetIHostById(hostId)
  1448. if err != nil {
  1449. return errors.Wrap(err, "svm.manager.GetIHostById(hostId)")
  1450. }
  1451. host := ihost.(*SHost)
  1452. targetHs = host.object.(*mo.HostSystem)
  1453. if len(targetHs.Datastore) < 1 {
  1454. return errors.Wrap(fmt.Errorf("target host has no datastore"), "relocate")
  1455. }
  1456. rp, err := host.GetResourcePool()
  1457. if err != nil {
  1458. return errors.Wrapf(err, "GetResourcePool")
  1459. }
  1460. pool := rp.Reference()
  1461. ctx := svm.manager.context
  1462. config := types.VirtualMachineRelocateSpec{}
  1463. config.Pool = &pool
  1464. hrs := targetHs.Reference()
  1465. config.Host = &hrs
  1466. dss := []types.ManagedObjectReference{}
  1467. var datastores []mo.Datastore
  1468. for i := range svm.vdisks {
  1469. ds := svm.vdisks[i].getBackingInfo().GetDatastore()
  1470. if ds != nil {
  1471. dss = append(dss, *ds)
  1472. }
  1473. }
  1474. dc, err := host.GetDatacenter()
  1475. if err != nil {
  1476. return err
  1477. }
  1478. err = host.manager.references2Objects(dss, DATASTORE_PROPS, &datastores)
  1479. if err != nil {
  1480. return err
  1481. }
  1482. isShared := true
  1483. for i := 0; i < len(datastores); i += 1 {
  1484. ds := NewDatastore(host.manager, &datastores[i], dc)
  1485. storageType := ds.GetStorageType()
  1486. if !utils.IsInStringArray(storageType, []string{api.STORAGE_NAS, api.STORAGE_NFS, api.STORAGE_VSAN}) {
  1487. isShared = false
  1488. break
  1489. }
  1490. }
  1491. if !isShared {
  1492. err := host.fetchDatastores()
  1493. if err != nil {
  1494. return errors.Wrapf(err, "fetchDatastores")
  1495. }
  1496. max := int64(0)
  1497. for i := range host.datastores {
  1498. ds := host.datastores[i].(*SDatastore)
  1499. if ds.GetCapacityFreeMB() > max {
  1500. max = ds.GetCapacityFreeMB()
  1501. config.Datastore = &targetHs.Datastore[i]
  1502. }
  1503. }
  1504. }
  1505. task, err := svm.getVmObj().Relocate(ctx, config, types.VirtualMachineMovePriorityDefaultPriority)
  1506. if err != nil {
  1507. return errors.Wrap(err, "Relocate")
  1508. }
  1509. err = task.Wait(ctx)
  1510. if err != nil {
  1511. return errors.Wrap(err, "task.wait")
  1512. }
  1513. return nil
  1514. }
  1515. func (svm *SVirtualMachine) MigrateVM(hostId string) error {
  1516. return svm.relocate(hostId)
  1517. }
  1518. func (svm *SVirtualMachine) LiveMigrateVM(hostId string) error {
  1519. return svm.relocate(hostId)
  1520. }
  1521. func (svm *SVirtualMachine) GetIHostId() string {
  1522. ctx := svm.manager.context
  1523. hs, err := svm.getVmObj().HostSystem(ctx)
  1524. if err != nil {
  1525. log.Errorf("get HostSystem %s", err)
  1526. return ""
  1527. }
  1528. var moHost mo.HostSystem
  1529. err = svm.manager.reference2Object(hs.Reference(), HOST_SYSTEM_PROPS, &moHost)
  1530. if err != nil {
  1531. log.Errorf("hostsystem reference2Object %s", err)
  1532. return ""
  1533. }
  1534. shost := NewHost(svm.manager, &moHost, nil)
  1535. return shost.GetGlobalId()
  1536. }
  1537. func (svm *SVirtualMachine) IsTemplate() bool {
  1538. movm := svm.getVirtualMachine()
  1539. if tempalteNameRegex != nil && tempalteNameRegex.MatchString(svm.GetName()) && movm.Summary.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOff {
  1540. return true
  1541. }
  1542. return movm.Config != nil && movm.Config.Template
  1543. }
  1544. func (svm *SVirtualMachine) fetchSnapshots() {
  1545. movm := svm.getVirtualMachine()
  1546. if movm.Snapshot == nil {
  1547. return
  1548. }
  1549. svm.snapshots = svm.extractSnapshots(movm.Snapshot.RootSnapshotList, make([]SVirtualMachineSnapshot, 0, len(movm.Snapshot.RootSnapshotList)))
  1550. }
  1551. func (svm *SVirtualMachine) extractSnapshots(tree []types.VirtualMachineSnapshotTree, snapshots []SVirtualMachineSnapshot) []SVirtualMachineSnapshot {
  1552. for i := range tree {
  1553. snapshots = append(snapshots, SVirtualMachineSnapshot{
  1554. snapshotTree: tree[i],
  1555. vm: svm,
  1556. })
  1557. snapshots = svm.extractSnapshots(tree[i].ChildSnapshotList, snapshots)
  1558. }
  1559. return snapshots
  1560. }
  1561. func (svm *SVirtualMachine) GetInstanceSnapshots() ([]cloudprovider.ICloudInstanceSnapshot, error) {
  1562. if svm.snapshots == nil {
  1563. svm.fetchSnapshots()
  1564. }
  1565. ret := make([]cloudprovider.ICloudInstanceSnapshot, 0, len(svm.snapshots))
  1566. for i := range svm.snapshots {
  1567. ret = append(ret, &svm.snapshots[i])
  1568. }
  1569. return ret, nil
  1570. }
  1571. func (svm *SVirtualMachine) GetInstanceSnapshot(idStr string) (cloudprovider.ICloudInstanceSnapshot, error) {
  1572. if svm.snapshots == nil {
  1573. svm.fetchSnapshots()
  1574. }
  1575. for i := range svm.snapshots {
  1576. if svm.snapshots[i].GetGlobalId() == idStr {
  1577. // copyone
  1578. sp := svm.snapshots[i]
  1579. return &sp, nil
  1580. }
  1581. }
  1582. return nil, errors.ErrNotFound
  1583. }
  1584. func (svm *SVirtualMachine) CreateInstanceSnapshot(ctx context.Context, name string, desc string) (cloudprovider.ICloudInstanceSnapshot, error) {
  1585. ovm := svm.getVmObj()
  1586. task, err := ovm.CreateSnapshot(ctx, name, desc, false, false)
  1587. if err != nil {
  1588. return nil, errors.Wrap(err, "CreateSnapshot")
  1589. }
  1590. info, err := task.WaitForResult(ctx, nil)
  1591. if err != nil {
  1592. return nil, errors.Wrap(err, "task.Wait")
  1593. }
  1594. sp := info.Result.(types.ManagedObjectReference)
  1595. err = svm.Refresh()
  1596. if err != nil {
  1597. return nil, errors.Wrap(err, "create successfully")
  1598. }
  1599. svm.fetchSnapshots()
  1600. for i := range svm.snapshots {
  1601. if svm.snapshots[i].snapshotTree.Snapshot == sp {
  1602. // copyone
  1603. sp := svm.snapshots[i]
  1604. return &sp, nil
  1605. }
  1606. }
  1607. return nil, errors.Wrap(errors.ErrNotFound, "create successfully")
  1608. }
  1609. func (svm *SVirtualMachine) ResetToInstanceSnapshot(ctx context.Context, idStr string) error {
  1610. cloudIsp, err := svm.GetInstanceSnapshot(idStr)
  1611. if err != nil {
  1612. return errors.Wrap(err, "GetInstanceSnapshot")
  1613. }
  1614. isp := cloudIsp.(*SVirtualMachineSnapshot)
  1615. req := types.RevertToSnapshot_Task{
  1616. This: isp.snapshotTree.Snapshot.Reference(),
  1617. }
  1618. res, err := methods.RevertToSnapshot_Task(ctx, svm.manager.client.Client, &req)
  1619. if err != nil {
  1620. return errors.Wrap(err, "RevertToSnapshot_Task")
  1621. }
  1622. return object.NewTask(svm.manager.client.Client, res.Returnval).Wait(ctx)
  1623. }
  1624. func (vm *SVirtualMachine) GetDatastores() ([]*SDatastore, error) {
  1625. dsList := make([]*SDatastore, 0)
  1626. dss := vm.getVirtualMachine().Datastore
  1627. for i := range dss {
  1628. var moStore mo.Datastore
  1629. err := vm.manager.reference2Object(dss[i].Reference(), DATASTORE_PROPS, &moStore)
  1630. if err != nil {
  1631. log.Errorf("datastore reference2Object %s", err)
  1632. return nil, errors.Wrap(err, "reference2Object")
  1633. }
  1634. ds := NewDatastore(vm.manager, &moStore, vm.datacenter)
  1635. dsList = append(dsList, ds)
  1636. }
  1637. return dsList, nil
  1638. }
  1639. func (vm *SVirtualMachine) GetDatastoreNames() []string {
  1640. dss, err := vm.GetDatastores()
  1641. if err != nil {
  1642. log.Errorf("GetDatastores fail %s", err)
  1643. return nil
  1644. }
  1645. names := make([]string, 0, len(dss))
  1646. for i := range dss {
  1647. names = append(names, dss[i].GetName())
  1648. }
  1649. return names
  1650. }