virtual_machine.go 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777
  1. /*
  2. Copyright (c) 2017-2018 VMware, Inc. All Rights Reserved.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package simulator
  14. import (
  15. "bytes"
  16. "fmt"
  17. "io/ioutil"
  18. "log"
  19. "net"
  20. "os"
  21. "path"
  22. "path/filepath"
  23. "strconv"
  24. "strings"
  25. "sync/atomic"
  26. "time"
  27. "github.com/google/uuid"
  28. "github.com/vmware/govmomi/object"
  29. "github.com/vmware/govmomi/simulator/esx"
  30. "github.com/vmware/govmomi/vim25/methods"
  31. "github.com/vmware/govmomi/vim25/mo"
  32. "github.com/vmware/govmomi/vim25/soap"
  33. "github.com/vmware/govmomi/vim25/types"
  34. )
  35. type VirtualMachine struct {
  36. mo.VirtualMachine
  37. log string
  38. sid int32
  39. run container
  40. }
  41. func NewVirtualMachine(parent types.ManagedObjectReference, spec *types.VirtualMachineConfigSpec) (*VirtualMachine, types.BaseMethodFault) {
  42. vm := &VirtualMachine{}
  43. vm.Parent = &parent
  44. Map.Get(parent).(*Folder).putChild(vm)
  45. if spec.Name == "" {
  46. return vm, &types.InvalidVmConfig{Property: "configSpec.name"}
  47. }
  48. if spec.Files == nil || spec.Files.VmPathName == "" {
  49. return vm, &types.InvalidVmConfig{Property: "configSpec.files.vmPathName"}
  50. }
  51. rspec := types.DefaultResourceConfigSpec()
  52. vm.Guest = &types.GuestInfo{}
  53. vm.Config = &types.VirtualMachineConfigInfo{
  54. ExtraConfig: []types.BaseOptionValue{&types.OptionValue{Key: "govcsim", Value: "TRUE"}},
  55. Tools: &types.ToolsConfigInfo{},
  56. MemoryAllocation: &rspec.MemoryAllocation,
  57. CpuAllocation: &rspec.CpuAllocation,
  58. }
  59. vm.Layout = &types.VirtualMachineFileLayout{}
  60. vm.LayoutEx = &types.VirtualMachineFileLayoutEx{
  61. Timestamp: time.Now(),
  62. }
  63. vm.Snapshot = nil // intentionally set to nil until a snapshot is created
  64. vm.Storage = &types.VirtualMachineStorageInfo{
  65. Timestamp: time.Now(),
  66. }
  67. vm.Summary.Guest = &types.VirtualMachineGuestSummary{}
  68. vm.Summary.Vm = &vm.Self
  69. vm.Summary.Storage = &types.VirtualMachineStorageSummary{
  70. Timestamp: time.Now(),
  71. }
  72. // Append VM Name as the directory name if not specified
  73. if strings.HasSuffix(spec.Files.VmPathName, "]") { // e.g. "[datastore1]"
  74. spec.Files.VmPathName += " " + spec.Name
  75. }
  76. if !strings.HasSuffix(spec.Files.VmPathName, ".vmx") {
  77. spec.Files.VmPathName = path.Join(spec.Files.VmPathName, spec.Name+".vmx")
  78. }
  79. dsPath := path.Dir(spec.Files.VmPathName)
  80. defaults := types.VirtualMachineConfigSpec{
  81. NumCPUs: 1,
  82. NumCoresPerSocket: 1,
  83. MemoryMB: 32,
  84. Uuid: uuid.New().String(),
  85. InstanceUuid: uuid.New().String(),
  86. Version: esx.HardwareVersion,
  87. Files: &types.VirtualMachineFileInfo{
  88. SnapshotDirectory: dsPath,
  89. SuspendDirectory: dsPath,
  90. LogDirectory: dsPath,
  91. },
  92. }
  93. // Add the default devices
  94. defaults.DeviceChange, _ = object.VirtualDeviceList(esx.VirtualDevice).ConfigSpec(types.VirtualDeviceConfigSpecOperationAdd)
  95. err := vm.configure(&defaults)
  96. if err != nil {
  97. return vm, err
  98. }
  99. vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff
  100. vm.Runtime.ConnectionState = types.VirtualMachineConnectionStateConnected
  101. vm.Summary.Runtime = vm.Runtime
  102. vm.Summary.QuickStats.GuestHeartbeatStatus = types.ManagedEntityStatusGray
  103. vm.Summary.OverallStatus = types.ManagedEntityStatusGreen
  104. vm.ConfigStatus = types.ManagedEntityStatusGreen
  105. return vm, nil
  106. }
  107. func (vm *VirtualMachine) event() types.VmEvent {
  108. host := Map.Get(*vm.Runtime.Host).(*HostSystem)
  109. return types.VmEvent{
  110. Event: types.Event{
  111. Datacenter: datacenterEventArgument(host),
  112. ComputeResource: host.eventArgumentParent(),
  113. Host: host.eventArgument(),
  114. Vm: &types.VmEventArgument{
  115. EntityEventArgument: types.EntityEventArgument{Name: vm.Name},
  116. Vm: vm.Self,
  117. },
  118. },
  119. }
  120. }
  121. func (vm *VirtualMachine) apply(spec *types.VirtualMachineConfigSpec) {
  122. if spec.Files == nil {
  123. spec.Files = new(types.VirtualMachineFileInfo)
  124. }
  125. apply := []struct {
  126. src string
  127. dst *string
  128. }{
  129. {spec.AlternateGuestName, &vm.Config.AlternateGuestName},
  130. {spec.Annotation, &vm.Config.Annotation},
  131. {spec.Firmware, &vm.Config.Firmware},
  132. {spec.InstanceUuid, &vm.Config.InstanceUuid},
  133. {spec.LocationId, &vm.Config.LocationId},
  134. {spec.NpivWorldWideNameType, &vm.Config.NpivWorldWideNameType},
  135. {spec.Name, &vm.Name},
  136. {spec.Name, &vm.Config.Name},
  137. {spec.Name, &vm.Summary.Config.Name},
  138. {spec.GuestId, &vm.Config.GuestId},
  139. {spec.GuestId, &vm.Config.GuestFullName},
  140. {spec.GuestId, &vm.Summary.Guest.GuestId},
  141. {spec.GuestId, &vm.Summary.Config.GuestId},
  142. {spec.GuestId, &vm.Summary.Config.GuestFullName},
  143. {spec.Uuid, &vm.Config.Uuid},
  144. {spec.Uuid, &vm.Summary.Config.Uuid},
  145. {spec.InstanceUuid, &vm.Config.InstanceUuid},
  146. {spec.InstanceUuid, &vm.Summary.Config.InstanceUuid},
  147. {spec.Version, &vm.Config.Version},
  148. {spec.Files.VmPathName, &vm.Config.Files.VmPathName},
  149. {spec.Files.VmPathName, &vm.Summary.Config.VmPathName},
  150. {spec.Files.SnapshotDirectory, &vm.Config.Files.SnapshotDirectory},
  151. {spec.Files.SuspendDirectory, &vm.Config.Files.SuspendDirectory},
  152. {spec.Files.LogDirectory, &vm.Config.Files.LogDirectory},
  153. }
  154. for _, f := range apply {
  155. if f.src != "" {
  156. *f.dst = f.src
  157. }
  158. }
  159. applyb := []struct {
  160. src *bool
  161. dst **bool
  162. }{
  163. {spec.NestedHVEnabled, &vm.Config.NestedHVEnabled},
  164. {spec.CpuHotAddEnabled, &vm.Config.CpuHotAddEnabled},
  165. {spec.CpuHotRemoveEnabled, &vm.Config.CpuHotRemoveEnabled},
  166. {spec.GuestAutoLockEnabled, &vm.Config.GuestAutoLockEnabled},
  167. {spec.MemoryHotAddEnabled, &vm.Config.MemoryHotAddEnabled},
  168. {spec.MemoryReservationLockedToMax, &vm.Config.MemoryReservationLockedToMax},
  169. {spec.MessageBusTunnelEnabled, &vm.Config.MessageBusTunnelEnabled},
  170. {spec.NpivTemporaryDisabled, &vm.Config.NpivTemporaryDisabled},
  171. {spec.NpivOnNonRdmDisks, &vm.Config.NpivOnNonRdmDisks},
  172. {spec.ChangeTrackingEnabled, &vm.Config.ChangeTrackingEnabled},
  173. }
  174. for _, f := range applyb {
  175. if f.src != nil {
  176. *f.dst = f.src
  177. }
  178. }
  179. if spec.Flags != nil {
  180. vm.Config.Flags = *spec.Flags
  181. }
  182. if spec.LatencySensitivity != nil {
  183. vm.Config.LatencySensitivity = spec.LatencySensitivity
  184. }
  185. if spec.ManagedBy != nil {
  186. vm.Config.ManagedBy = spec.ManagedBy
  187. }
  188. if spec.BootOptions != nil {
  189. vm.Config.BootOptions = spec.BootOptions
  190. }
  191. if spec.RepConfig != nil {
  192. vm.Config.RepConfig = spec.RepConfig
  193. }
  194. if spec.Tools != nil {
  195. vm.Config.Tools = spec.Tools
  196. }
  197. if spec.ConsolePreferences != nil {
  198. vm.Config.ConsolePreferences = spec.ConsolePreferences
  199. }
  200. if spec.CpuAffinity != nil {
  201. vm.Config.CpuAffinity = spec.CpuAffinity
  202. }
  203. if spec.CpuAllocation != nil {
  204. vm.Config.CpuAllocation = spec.CpuAllocation
  205. }
  206. if spec.MemoryAffinity != nil {
  207. vm.Config.MemoryAffinity = spec.MemoryAffinity
  208. }
  209. if spec.MemoryAllocation != nil {
  210. vm.Config.MemoryAllocation = spec.MemoryAllocation
  211. }
  212. if spec.LatencySensitivity != nil {
  213. vm.Config.LatencySensitivity = spec.LatencySensitivity
  214. }
  215. if spec.MemoryMB != 0 {
  216. vm.Config.Hardware.MemoryMB = int32(spec.MemoryMB)
  217. vm.Summary.Config.MemorySizeMB = vm.Config.Hardware.MemoryMB
  218. }
  219. if spec.NumCPUs != 0 {
  220. vm.Config.Hardware.NumCPU = spec.NumCPUs
  221. vm.Summary.Config.NumCpu = vm.Config.Hardware.NumCPU
  222. }
  223. if spec.NumCoresPerSocket != 0 {
  224. vm.Config.Hardware.NumCoresPerSocket = spec.NumCoresPerSocket
  225. }
  226. var changes []types.PropertyChange
  227. for _, c := range spec.ExtraConfig {
  228. val := c.GetOptionValue()
  229. key := strings.TrimPrefix(val.Key, "SET.")
  230. if key == val.Key {
  231. vm.Config.ExtraConfig = append(vm.Config.ExtraConfig, c)
  232. continue
  233. }
  234. changes = append(changes, types.PropertyChange{Name: key, Val: val.Value})
  235. switch key {
  236. case "guest.ipAddress":
  237. ip := val.Value.(string)
  238. vm.Guest.Net[0].IpAddress = []string{ip}
  239. changes = append(changes,
  240. types.PropertyChange{Name: "summary." + key, Val: ip},
  241. types.PropertyChange{Name: "guest.net", Val: vm.Guest.Net},
  242. )
  243. case "guest.hostName":
  244. changes = append(changes,
  245. types.PropertyChange{Name: "summary." + key, Val: val.Value},
  246. )
  247. }
  248. }
  249. if len(changes) != 0 {
  250. Map.Update(vm, changes)
  251. }
  252. vm.Config.Modified = time.Now()
  253. }
  254. func validateGuestID(id string) types.BaseMethodFault {
  255. for _, x := range GuestID {
  256. if id == string(x) {
  257. return nil
  258. }
  259. }
  260. return &types.InvalidArgument{InvalidProperty: "configSpec.guestId"}
  261. }
  262. func (vm *VirtualMachine) configure(spec *types.VirtualMachineConfigSpec) types.BaseMethodFault {
  263. vm.apply(spec)
  264. if spec.MemoryAllocation != nil {
  265. if err := updateResourceAllocation("memory", spec.MemoryAllocation, vm.Config.MemoryAllocation); err != nil {
  266. return err
  267. }
  268. }
  269. if spec.CpuAllocation != nil {
  270. if err := updateResourceAllocation("cpu", spec.CpuAllocation, vm.Config.CpuAllocation); err != nil {
  271. return err
  272. }
  273. }
  274. if spec.GuestId != "" {
  275. if err := validateGuestID(spec.GuestId); err != nil {
  276. return err
  277. }
  278. }
  279. return vm.configureDevices(spec)
  280. }
  281. func getVMFileType(fileName string) types.VirtualMachineFileLayoutExFileType {
  282. var fileType types.VirtualMachineFileLayoutExFileType
  283. fileExt := path.Ext(fileName)
  284. fileNameNoExt := strings.TrimSuffix(fileName, fileExt)
  285. switch fileExt {
  286. case ".vmx":
  287. fileType = types.VirtualMachineFileLayoutExFileTypeConfig
  288. case ".core":
  289. fileType = types.VirtualMachineFileLayoutExFileTypeCore
  290. case ".vmdk":
  291. fileType = types.VirtualMachineFileLayoutExFileTypeDiskDescriptor
  292. if strings.HasSuffix(fileNameNoExt, "-digest") {
  293. fileType = types.VirtualMachineFileLayoutExFileTypeDigestDescriptor
  294. }
  295. extentSuffixes := []string{"-flat", "-delta", "-s", "-rdm", "-rdmp"}
  296. for _, suffix := range extentSuffixes {
  297. if strings.HasSuffix(fileNameNoExt, suffix) {
  298. fileType = types.VirtualMachineFileLayoutExFileTypeDiskExtent
  299. } else if strings.HasSuffix(fileNameNoExt, "-digest"+suffix) {
  300. fileType = types.VirtualMachineFileLayoutExFileTypeDigestExtent
  301. }
  302. }
  303. case ".psf":
  304. fileType = types.VirtualMachineFileLayoutExFileTypeDiskReplicationState
  305. case ".vmxf":
  306. fileType = types.VirtualMachineFileLayoutExFileTypeExtendedConfig
  307. case ".vmft":
  308. fileType = types.VirtualMachineFileLayoutExFileTypeFtMetadata
  309. case ".log":
  310. fileType = types.VirtualMachineFileLayoutExFileTypeLog
  311. case ".nvram":
  312. fileType = types.VirtualMachineFileLayoutExFileTypeNvram
  313. case ".png", ".bmp":
  314. fileType = types.VirtualMachineFileLayoutExFileTypeScreenshot
  315. case ".vmsn":
  316. fileType = types.VirtualMachineFileLayoutExFileTypeSnapshotData
  317. case ".vmsd":
  318. fileType = types.VirtualMachineFileLayoutExFileTypeSnapshotList
  319. case ".xml":
  320. if strings.HasSuffix(fileNameNoExt, "-aux") {
  321. fileType = types.VirtualMachineFileLayoutExFileTypeSnapshotManifestList
  322. }
  323. case ".stat":
  324. fileType = types.VirtualMachineFileLayoutExFileTypeStat
  325. case ".vmss":
  326. fileType = types.VirtualMachineFileLayoutExFileTypeSuspend
  327. case ".vmem":
  328. if strings.Contains(fileNameNoExt, "Snapshot") {
  329. fileType = types.VirtualMachineFileLayoutExFileTypeSnapshotMemory
  330. } else {
  331. fileType = types.VirtualMachineFileLayoutExFileTypeSuspendMemory
  332. }
  333. case ".vswp":
  334. if strings.HasPrefix(fileNameNoExt, "vmx-") {
  335. fileType = types.VirtualMachineFileLayoutExFileTypeUwswap
  336. } else {
  337. fileType = types.VirtualMachineFileLayoutExFileTypeSwap
  338. }
  339. case "":
  340. if strings.HasPrefix(fileNameNoExt, "imcf-") {
  341. fileType = types.VirtualMachineFileLayoutExFileTypeGuestCustomization
  342. }
  343. }
  344. return fileType
  345. }
  346. func (vm *VirtualMachine) addFileLayoutEx(datastorePath object.DatastorePath, fileSize int64) int32 {
  347. var newKey int32
  348. for _, layoutFile := range vm.LayoutEx.File {
  349. if layoutFile.Name == datastorePath.String() {
  350. return layoutFile.Key
  351. }
  352. if layoutFile.Key >= newKey {
  353. newKey = layoutFile.Key + 1
  354. }
  355. }
  356. fileType := getVMFileType(filepath.Base(datastorePath.Path))
  357. switch fileType {
  358. case types.VirtualMachineFileLayoutExFileTypeNvram, types.VirtualMachineFileLayoutExFileTypeSnapshotList:
  359. vm.addConfigLayout(datastorePath.Path)
  360. case types.VirtualMachineFileLayoutExFileTypeLog:
  361. vm.addLogLayout(datastorePath.Path)
  362. case types.VirtualMachineFileLayoutExFileTypeSwap:
  363. vm.addSwapLayout(datastorePath.String())
  364. }
  365. vm.LayoutEx.File = append(vm.LayoutEx.File, types.VirtualMachineFileLayoutExFileInfo{
  366. Accessible: types.NewBool(true),
  367. BackingObjectId: "",
  368. Key: newKey,
  369. Name: datastorePath.String(),
  370. Size: fileSize,
  371. Type: string(fileType),
  372. UniqueSize: fileSize,
  373. })
  374. vm.LayoutEx.Timestamp = time.Now()
  375. vm.updateStorage()
  376. return newKey
  377. }
  378. func (vm *VirtualMachine) addConfigLayout(name string) {
  379. for _, config := range vm.Layout.ConfigFile {
  380. if config == name {
  381. return
  382. }
  383. }
  384. vm.Layout.ConfigFile = append(vm.Layout.ConfigFile, name)
  385. vm.updateStorage()
  386. }
  387. func (vm *VirtualMachine) addLogLayout(name string) {
  388. for _, log := range vm.Layout.LogFile {
  389. if log == name {
  390. return
  391. }
  392. }
  393. vm.Layout.LogFile = append(vm.Layout.LogFile, name)
  394. vm.updateStorage()
  395. }
  396. func (vm *VirtualMachine) addSwapLayout(name string) {
  397. vm.Layout.SwapFile = name
  398. vm.updateStorage()
  399. }
  400. func (vm *VirtualMachine) addSnapshotLayout(snapshot types.ManagedObjectReference, dataKey int32) {
  401. for _, snapshotLayout := range vm.Layout.Snapshot {
  402. if snapshotLayout.Key == snapshot {
  403. return
  404. }
  405. }
  406. var snapshotFiles []string
  407. for _, file := range vm.LayoutEx.File {
  408. if file.Key == dataKey || file.Type == "diskDescriptor" {
  409. snapshotFiles = append(snapshotFiles, file.Name)
  410. }
  411. }
  412. vm.Layout.Snapshot = append(vm.Layout.Snapshot, types.VirtualMachineFileLayoutSnapshotLayout{
  413. Key: snapshot,
  414. SnapshotFile: snapshotFiles,
  415. })
  416. vm.updateStorage()
  417. }
  418. func (vm *VirtualMachine) addSnapshotLayoutEx(snapshot types.ManagedObjectReference, dataKey int32, memoryKey int32) {
  419. for _, snapshotLayoutEx := range vm.LayoutEx.Snapshot {
  420. if snapshotLayoutEx.Key == snapshot {
  421. return
  422. }
  423. }
  424. vm.LayoutEx.Snapshot = append(vm.LayoutEx.Snapshot, types.VirtualMachineFileLayoutExSnapshotLayout{
  425. DataKey: dataKey,
  426. Disk: vm.LayoutEx.Disk,
  427. Key: snapshot,
  428. MemoryKey: memoryKey,
  429. })
  430. vm.LayoutEx.Timestamp = time.Now()
  431. vm.updateStorage()
  432. }
  433. // Updates both vm.Layout.Disk and vm.LayoutEx.Disk
  434. func (vm *VirtualMachine) updateDiskLayouts() types.BaseMethodFault {
  435. var disksLayout []types.VirtualMachineFileLayoutDiskLayout
  436. var disksLayoutEx []types.VirtualMachineFileLayoutExDiskLayout
  437. disks := object.VirtualDeviceList(vm.Config.Hardware.Device).SelectByType((*types.VirtualDisk)(nil))
  438. for _, disk := range disks {
  439. disk := disk.(*types.VirtualDisk)
  440. diskBacking := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
  441. diskLayout := &types.VirtualMachineFileLayoutDiskLayout{Key: disk.Key}
  442. diskLayoutEx := &types.VirtualMachineFileLayoutExDiskLayout{Key: disk.Key}
  443. // Iterate through disk and its parents
  444. for {
  445. dFileName := diskBacking.GetVirtualDeviceFileBackingInfo().FileName
  446. var fileKeys []int32
  447. dm := Map.VirtualDiskManager()
  448. // Add disk descriptor and extent files
  449. for _, diskName := range dm.names(dFileName) {
  450. // get full path including datastore location
  451. p, fault := parseDatastorePath(diskName)
  452. if fault != nil {
  453. return fault
  454. }
  455. datastore := vm.useDatastore(p.Datastore)
  456. dFilePath := path.Join(datastore.Info.GetDatastoreInfo().Url, p.Path)
  457. var fileSize int64
  458. // If file can not be opened - fileSize will be 0
  459. if dFileInfo, err := os.Stat(dFilePath); err == nil {
  460. fileSize = dFileInfo.Size()
  461. }
  462. diskKey := vm.addFileLayoutEx(*p, fileSize)
  463. fileKeys = append(fileKeys, diskKey)
  464. }
  465. diskLayout.DiskFile = append(diskLayout.DiskFile, dFileName)
  466. diskLayoutEx.Chain = append(diskLayoutEx.Chain, types.VirtualMachineFileLayoutExDiskUnit{
  467. FileKey: fileKeys,
  468. })
  469. if parent := diskBacking.Parent; parent != nil {
  470. diskBacking = parent
  471. } else {
  472. break
  473. }
  474. }
  475. disksLayout = append(disksLayout, *diskLayout)
  476. disksLayoutEx = append(disksLayoutEx, *diskLayoutEx)
  477. }
  478. vm.Layout.Disk = disksLayout
  479. vm.LayoutEx.Disk = disksLayoutEx
  480. vm.LayoutEx.Timestamp = time.Now()
  481. vm.updateStorage()
  482. return nil
  483. }
  484. func (vm *VirtualMachine) updateStorage() types.BaseMethodFault {
  485. // Committed - sum of Size for each file in vm.LayoutEx.File
  486. // Unshared - sum of Size for each disk (.vmdk) in vm.LayoutEx.File
  487. // Uncommitted - disk capacity minus disk usage (only currently used disk)
  488. var datastoresUsage []types.VirtualMachineUsageOnDatastore
  489. disks := object.VirtualDeviceList(vm.Config.Hardware.Device).SelectByType((*types.VirtualDisk)(nil))
  490. for _, file := range vm.LayoutEx.File {
  491. p, fault := parseDatastorePath(file.Name)
  492. if fault != nil {
  493. return fault
  494. }
  495. datastore := vm.useDatastore(p.Datastore)
  496. dsUsage := &types.VirtualMachineUsageOnDatastore{
  497. Datastore: datastore.Self,
  498. }
  499. for idx, usage := range datastoresUsage {
  500. if usage.Datastore == datastore.Self {
  501. datastoresUsage = append(datastoresUsage[:idx], datastoresUsage[idx+1:]...)
  502. dsUsage = &usage
  503. break
  504. }
  505. }
  506. dsUsage.Committed = file.Size
  507. if path.Ext(file.Name) == ".vmdk" {
  508. dsUsage.Unshared = file.Size
  509. }
  510. for _, disk := range disks {
  511. disk := disk.(*types.VirtualDisk)
  512. backing := disk.Backing.(types.BaseVirtualDeviceFileBackingInfo).GetVirtualDeviceFileBackingInfo()
  513. if backing.FileName == file.Name {
  514. dsUsage.Uncommitted = disk.CapacityInBytes
  515. }
  516. }
  517. datastoresUsage = append(datastoresUsage, *dsUsage)
  518. }
  519. vm.Storage.PerDatastoreUsage = datastoresUsage
  520. vm.Storage.Timestamp = time.Now()
  521. storageSummary := &types.VirtualMachineStorageSummary{
  522. Timestamp: time.Now(),
  523. }
  524. for _, usage := range datastoresUsage {
  525. storageSummary.Committed += usage.Committed
  526. storageSummary.Uncommitted += usage.Uncommitted
  527. storageSummary.Unshared += usage.Unshared
  528. }
  529. vm.Summary.Storage = storageSummary
  530. return nil
  531. }
  532. func (vm *VirtualMachine) RefreshStorageInfo(ctx *Context, req *types.RefreshStorageInfo) soap.HasFault {
  533. body := new(methods.RefreshStorageInfoBody)
  534. if vm.Runtime.Host == nil {
  535. // VM not fully created
  536. return body
  537. }
  538. // Validate that all files in vm.LayoutEx.File can still be found
  539. for idx := len(vm.LayoutEx.File) - 1; idx >= 0; idx-- {
  540. file := vm.LayoutEx.File[idx]
  541. p, fault := parseDatastorePath(file.Name)
  542. if fault != nil {
  543. body.Fault_ = Fault("", fault)
  544. return body
  545. }
  546. if _, err := os.Stat(p.String()); err != nil {
  547. vm.LayoutEx.File = append(vm.LayoutEx.File[:idx], vm.LayoutEx.File[idx+1:]...)
  548. }
  549. }
  550. // Directories will be used to locate VM files.
  551. // Does not include information about virtual disk file locations.
  552. locations := []string{
  553. vm.Config.Files.VmPathName,
  554. vm.Config.Files.SnapshotDirectory,
  555. vm.Config.Files.LogDirectory,
  556. vm.Config.Files.SuspendDirectory,
  557. vm.Config.Files.FtMetadataDirectory,
  558. }
  559. for _, directory := range locations {
  560. if directory == "" {
  561. continue
  562. }
  563. p, fault := parseDatastorePath(directory)
  564. if fault != nil {
  565. body.Fault_ = Fault("", fault)
  566. return body
  567. }
  568. datastore := vm.useDatastore(p.Datastore)
  569. directory := path.Join(datastore.Info.GetDatastoreInfo().Url, p.Path)
  570. if path.Ext(p.Path) == ".vmx" {
  571. directory = path.Dir(directory) // vm.Config.Files.VmPathName can be a directory or full path to .vmx
  572. }
  573. if _, err := os.Stat(directory); err != nil {
  574. // Can not access the directory
  575. continue
  576. }
  577. files, err := ioutil.ReadDir(directory)
  578. if err != nil {
  579. body.Fault_ = soap.ToSoapFault(err)
  580. return body
  581. }
  582. for _, file := range files {
  583. datastorePath := object.DatastorePath{
  584. Datastore: p.Datastore,
  585. Path: strings.TrimPrefix(file.Name(), datastore.Info.GetDatastoreInfo().Url),
  586. }
  587. vm.addFileLayoutEx(datastorePath, file.Size())
  588. }
  589. }
  590. fault := vm.updateDiskLayouts()
  591. if fault != nil {
  592. body.Fault_ = Fault("", fault)
  593. return body
  594. }
  595. vm.LayoutEx.Timestamp = time.Now()
  596. return body
  597. }
  598. func (vm *VirtualMachine) useDatastore(name string) *Datastore {
  599. host := Map.Get(*vm.Runtime.Host).(*HostSystem)
  600. ds := Map.FindByName(name, host.Datastore).(*Datastore)
  601. if FindReference(vm.Datastore, ds.Self) == nil {
  602. vm.Datastore = append(vm.Datastore, ds.Self)
  603. }
  604. return ds
  605. }
  606. func (vm *VirtualMachine) createFile(spec string, name string, register bool) (*os.File, types.BaseMethodFault) {
  607. p, fault := parseDatastorePath(spec)
  608. if fault != nil {
  609. return nil, fault
  610. }
  611. ds := vm.useDatastore(p.Datastore)
  612. file := path.Join(ds.Info.GetDatastoreInfo().Url, p.Path)
  613. if name != "" {
  614. if path.Ext(p.Path) == ".vmx" {
  615. file = path.Dir(file) // vm.Config.Files.VmPathName can be a directory or full path to .vmx
  616. }
  617. file = path.Join(file, name)
  618. }
  619. if register {
  620. f, err := os.Open(file)
  621. if err != nil {
  622. log.Printf("register %s: %s", vm.Reference(), err)
  623. if os.IsNotExist(err) {
  624. return nil, &types.NotFound{}
  625. }
  626. return nil, &types.InvalidArgument{}
  627. }
  628. return f, nil
  629. }
  630. dir := path.Dir(file)
  631. _ = os.MkdirAll(dir, 0700)
  632. _, err := os.Stat(file)
  633. if err == nil {
  634. return nil, &types.FileAlreadyExists{
  635. FileFault: types.FileFault{
  636. File: file,
  637. },
  638. }
  639. }
  640. f, err := os.Create(file)
  641. if err != nil {
  642. return nil, &types.FileFault{
  643. File: file,
  644. }
  645. }
  646. return f, nil
  647. }
  648. // Rather than keep an fd open for each VM, open/close the log for each messages.
  649. // This is ok for now as we do not do any heavy VM logging.
  650. func (vm *VirtualMachine) logPrintf(format string, v ...interface{}) {
  651. f, err := os.OpenFile(vm.log, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0)
  652. if err != nil {
  653. log.Println(err)
  654. return
  655. }
  656. log.New(f, "vmx ", log.Flags()).Printf(format, v...)
  657. _ = f.Close()
  658. }
  659. func (vm *VirtualMachine) create(spec *types.VirtualMachineConfigSpec, register bool) types.BaseMethodFault {
  660. vm.apply(spec)
  661. if spec.Version != "" {
  662. v := strings.TrimPrefix(spec.Version, "vmx-")
  663. _, err := strconv.Atoi(v)
  664. if err != nil {
  665. log.Printf("unsupported hardware version: %s", spec.Version)
  666. return new(types.NotSupported)
  667. }
  668. }
  669. files := []struct {
  670. spec string
  671. name string
  672. use *string
  673. }{
  674. {vm.Config.Files.VmPathName, "", nil},
  675. {vm.Config.Files.VmPathName, fmt.Sprintf("%s.nvram", vm.Name), nil},
  676. {vm.Config.Files.LogDirectory, "vmware.log", &vm.log},
  677. }
  678. for _, file := range files {
  679. f, err := vm.createFile(file.spec, file.name, register)
  680. if err != nil {
  681. return err
  682. }
  683. if file.use != nil {
  684. *file.use = f.Name()
  685. }
  686. _ = f.Close()
  687. }
  688. vm.logPrintf("created")
  689. return vm.configureDevices(spec)
  690. }
  691. var vmwOUI = net.HardwareAddr([]byte{0x0, 0xc, 0x29})
  692. // From http://pubs.vmware.com/vsphere-60/index.jsp?topic=%2Fcom.vmware.vsphere.networking.doc%2FGUID-DC7478FF-DC44-4625-9AD7-38208C56A552.html
  693. // "The host generates generateMAC addresses that consists of the VMware OUI 00:0C:29 and the last three octets in hexadecimal
  694. // format of the virtual machine UUID. The virtual machine UUID is based on a hash calculated by using the UUID of the
  695. // ESXi physical machine and the path to the configuration file (.vmx) of the virtual machine."
  696. func (vm *VirtualMachine) generateMAC() string {
  697. id := uuid.New() // Random is fine for now.
  698. offset := len(id) - len(vmwOUI)
  699. mac := append(vmwOUI, id[offset:]...)
  700. return mac.String()
  701. }
  702. func numberToString(n int64, sep rune) string {
  703. buf := &bytes.Buffer{}
  704. if n < 0 {
  705. n = -n
  706. buf.WriteRune('-')
  707. }
  708. s := strconv.FormatInt(n, 10)
  709. pos := 3 - (len(s) % 3)
  710. for i := 0; i < len(s); i++ {
  711. if pos == 3 {
  712. if i != 0 {
  713. buf.WriteRune(sep)
  714. }
  715. pos = 0
  716. }
  717. pos++
  718. buf.WriteByte(s[i])
  719. }
  720. return buf.String()
  721. }
  722. func getDiskSize(disk *types.VirtualDisk) int64 {
  723. if disk.CapacityInBytes == 0 {
  724. return disk.CapacityInKB * 1024
  725. }
  726. return disk.CapacityInBytes
  727. }
  728. func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, spec *types.VirtualDeviceConfigSpec) types.BaseMethodFault {
  729. device := spec.Device
  730. d := device.GetVirtualDevice()
  731. var controller types.BaseVirtualController
  732. if d.Key <= 0 {
  733. // Keys can't be negative; Key 0 is reserved
  734. d.Key = devices.NewKey()
  735. d.Key *= -1
  736. }
  737. // Choose a unique key
  738. for {
  739. if devices.FindByKey(d.Key) == nil {
  740. break
  741. }
  742. d.Key++
  743. }
  744. label := devices.Name(device)
  745. summary := label
  746. dc := Map.getEntityDatacenter(Map.Get(*vm.Parent).(mo.Entity))
  747. dm := Map.VirtualDiskManager()
  748. switch x := device.(type) {
  749. case types.BaseVirtualEthernetCard:
  750. controller = devices.PickController((*types.VirtualPCIController)(nil))
  751. var net types.ManagedObjectReference
  752. var name string
  753. switch b := d.Backing.(type) {
  754. case *types.VirtualEthernetCardNetworkBackingInfo:
  755. name = b.DeviceName
  756. summary = name
  757. net = Map.FindByName(b.DeviceName, dc.Network).Reference()
  758. b.Network = &net
  759. case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo:
  760. summary = fmt.Sprintf("DVSwitch: %s", b.Port.SwitchUuid)
  761. net.Type = "DistributedVirtualPortgroup"
  762. net.Value = b.Port.PortgroupKey
  763. }
  764. Map.Update(vm, []types.PropertyChange{
  765. {Name: "summary.config.numEthernetCards", Val: vm.Summary.Config.NumEthernetCards + 1},
  766. {Name: "network", Val: append(vm.Network, net)},
  767. })
  768. c := x.GetVirtualEthernetCard()
  769. if c.MacAddress == "" {
  770. c.MacAddress = vm.generateMAC()
  771. }
  772. if spec.Operation == types.VirtualDeviceConfigSpecOperationAdd {
  773. vm.Guest.Net = append(vm.Guest.Net, types.GuestNicInfo{
  774. Network: name,
  775. IpAddress: nil,
  776. MacAddress: c.MacAddress,
  777. Connected: true,
  778. DeviceConfigId: c.Key,
  779. })
  780. }
  781. case *types.VirtualDisk:
  782. summary = fmt.Sprintf("%s KB", numberToString(x.CapacityInKB, ','))
  783. switch b := d.Backing.(type) {
  784. case types.BaseVirtualDeviceFileBackingInfo:
  785. info := b.GetVirtualDeviceFileBackingInfo()
  786. var path object.DatastorePath
  787. path.FromString(info.FileName)
  788. if path.Path == "" {
  789. filename, err := vm.genVmdkPath(path)
  790. if err != nil {
  791. return err
  792. }
  793. info.FileName = filename
  794. }
  795. err := dm.createVirtualDisk(spec.FileOperation, &types.CreateVirtualDisk_Task{
  796. Datacenter: &dc.Self,
  797. Name: info.FileName,
  798. })
  799. if err != nil {
  800. return err
  801. }
  802. Map.Update(vm, []types.PropertyChange{
  803. {Name: "summary.config.numVirtualDisks", Val: vm.Summary.Config.NumVirtualDisks + 1},
  804. })
  805. p, _ := parseDatastorePath(info.FileName)
  806. host := Map.Get(*vm.Runtime.Host).(*HostSystem)
  807. entity := Map.FindByName(p.Datastore, host.Datastore)
  808. ref := entity.Reference()
  809. info.Datastore = &ref
  810. ds := entity.(*Datastore)
  811. // XXX: compare disk size and free space until windows stat is supported
  812. ds.Summary.FreeSpace -= getDiskSize(x)
  813. ds.Info.GetDatastoreInfo().FreeSpace = ds.Summary.FreeSpace
  814. vm.updateDiskLayouts()
  815. }
  816. }
  817. if d.UnitNumber == nil && controller != nil {
  818. devices.AssignController(device, controller)
  819. }
  820. if d.DeviceInfo == nil {
  821. d.DeviceInfo = &types.Description{
  822. Label: label,
  823. Summary: summary,
  824. }
  825. }
  826. return nil
  827. }
  828. func (vm *VirtualMachine) removeDevice(devices object.VirtualDeviceList, spec *types.VirtualDeviceConfigSpec) object.VirtualDeviceList {
  829. key := spec.Device.GetVirtualDevice().Key
  830. for i, d := range devices {
  831. if d.GetVirtualDevice().Key != key {
  832. continue
  833. }
  834. devices = append(devices[:i], devices[i+1:]...)
  835. switch device := spec.Device.(type) {
  836. case *types.VirtualDisk:
  837. if spec.FileOperation == types.VirtualDeviceConfigSpecFileOperationDestroy {
  838. var file string
  839. switch b := device.Backing.(type) {
  840. case types.BaseVirtualDeviceFileBackingInfo:
  841. file = b.GetVirtualDeviceFileBackingInfo().FileName
  842. p, _ := parseDatastorePath(file)
  843. host := Map.Get(*vm.Runtime.Host).(*HostSystem)
  844. ds := Map.FindByName(p.Datastore, host.Datastore).(*Datastore)
  845. ds.Summary.FreeSpace += getDiskSize(device)
  846. ds.Info.GetDatastoreInfo().FreeSpace = ds.Summary.FreeSpace
  847. }
  848. if file != "" {
  849. dc := Map.getEntityDatacenter(Map.Get(*vm.Parent).(mo.Entity))
  850. dm := Map.VirtualDiskManager()
  851. dm.DeleteVirtualDiskTask(&types.DeleteVirtualDisk_Task{
  852. Name: file,
  853. Datacenter: &dc.Self,
  854. })
  855. }
  856. }
  857. Map.Update(vm, []types.PropertyChange{
  858. {Name: "summary.config.numVirtualDisks", Val: vm.Summary.Config.NumVirtualDisks - 1},
  859. })
  860. vm.updateDiskLayouts()
  861. case types.BaseVirtualEthernetCard:
  862. var net types.ManagedObjectReference
  863. switch b := device.GetVirtualEthernetCard().Backing.(type) {
  864. case *types.VirtualEthernetCardNetworkBackingInfo:
  865. net = *b.Network
  866. case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo:
  867. net.Type = "DistributedVirtualPortgroup"
  868. net.Value = b.Port.PortgroupKey
  869. }
  870. networks := vm.Network
  871. RemoveReference(&networks, net)
  872. Map.Update(vm, []types.PropertyChange{
  873. {Name: "summary.config.numEthernetCards", Val: vm.Summary.Config.NumEthernetCards - 1},
  874. {Name: "network", Val: networks},
  875. })
  876. }
  877. break
  878. }
  879. return devices
  880. }
  881. func (vm *VirtualMachine) genVmdkPath(p object.DatastorePath) (string, types.BaseMethodFault) {
  882. if p.Datastore == "" {
  883. p.FromString(vm.Config.Files.VmPathName)
  884. }
  885. if p.Path == "" {
  886. p.Path = vm.Config.Name
  887. } else {
  888. p.Path = path.Dir(p.Path)
  889. }
  890. vmdir := p.String()
  891. index := 0
  892. for {
  893. var filename string
  894. if index == 0 {
  895. filename = fmt.Sprintf("%s.vmdk", vm.Config.Name)
  896. } else {
  897. filename = fmt.Sprintf("%s_%d.vmdk", vm.Config.Name, index)
  898. }
  899. f, err := vm.createFile(vmdir, filename, false)
  900. if err != nil {
  901. switch err.(type) {
  902. case *types.FileAlreadyExists:
  903. index++
  904. continue
  905. default:
  906. return "", err
  907. }
  908. }
  909. _ = f.Close()
  910. _ = os.Remove(f.Name())
  911. return path.Join(vmdir, filename), nil
  912. }
  913. }
  914. func (vm *VirtualMachine) configureDevices(spec *types.VirtualMachineConfigSpec) types.BaseMethodFault {
  915. devices := object.VirtualDeviceList(vm.Config.Hardware.Device)
  916. for i, change := range spec.DeviceChange {
  917. dspec := change.GetVirtualDeviceConfigSpec()
  918. device := dspec.Device.GetVirtualDevice()
  919. invalid := &types.InvalidDeviceSpec{DeviceIndex: int32(i)}
  920. switch dspec.Operation {
  921. case types.VirtualDeviceConfigSpecOperationAdd:
  922. if devices.FindByKey(device.Key) != nil && device.ControllerKey == 0 {
  923. // Note: real ESX does not allow adding base controllers (ControllerKey = 0)
  924. // after VM is created (returns success but device is not added).
  925. continue
  926. } else if device.UnitNumber != nil && devices.SelectByType(dspec.Device).Select(func(d types.BaseVirtualDevice) bool {
  927. base := d.GetVirtualDevice()
  928. if base.UnitNumber != nil {
  929. if base.ControllerKey != device.ControllerKey {
  930. return false
  931. }
  932. return *base.UnitNumber == *device.UnitNumber
  933. }
  934. return false
  935. }) != nil {
  936. // UnitNumber for this device type is taken
  937. return invalid
  938. }
  939. err := vm.configureDevice(devices, dspec)
  940. if err != nil {
  941. return err
  942. }
  943. devices = append(devices, dspec.Device)
  944. case types.VirtualDeviceConfigSpecOperationEdit:
  945. rspec := *dspec
  946. rspec.Device = devices.FindByKey(device.Key)
  947. if rspec.Device == nil {
  948. return invalid
  949. }
  950. devices = vm.removeDevice(devices, &rspec)
  951. device.DeviceInfo = nil // regenerate summary + label
  952. err := vm.configureDevice(devices, dspec)
  953. if err != nil {
  954. return err
  955. }
  956. devices = append(devices, dspec.Device)
  957. case types.VirtualDeviceConfigSpecOperationRemove:
  958. devices = vm.removeDevice(devices, dspec)
  959. }
  960. }
  961. Map.Update(vm, []types.PropertyChange{
  962. {Name: "config.hardware.device", Val: []types.BaseVirtualDevice(devices)},
  963. })
  964. vm.updateDiskLayouts()
  965. return nil
  966. }
  967. type powerVMTask struct {
  968. *VirtualMachine
  969. state types.VirtualMachinePowerState
  970. ctx *Context
  971. }
  972. func (c *powerVMTask) Run(task *Task) (types.AnyType, types.BaseMethodFault) {
  973. c.logPrintf("running power task: requesting %s, existing %s",
  974. c.state, c.VirtualMachine.Runtime.PowerState)
  975. if c.VirtualMachine.Runtime.PowerState == c.state {
  976. return nil, &types.InvalidPowerState{
  977. RequestedState: c.state,
  978. ExistingState: c.VirtualMachine.Runtime.PowerState,
  979. }
  980. }
  981. var boot types.AnyType
  982. if c.state == types.VirtualMachinePowerStatePoweredOn {
  983. boot = time.Now()
  984. }
  985. event := c.event()
  986. switch c.state {
  987. case types.VirtualMachinePowerStatePoweredOn:
  988. c.run.start(c.VirtualMachine)
  989. c.ctx.postEvent(
  990. &types.VmStartingEvent{VmEvent: event},
  991. &types.VmPoweredOnEvent{VmEvent: event},
  992. )
  993. case types.VirtualMachinePowerStatePoweredOff:
  994. c.run.stop(c.VirtualMachine)
  995. c.ctx.postEvent(
  996. &types.VmStoppingEvent{VmEvent: event},
  997. &types.VmPoweredOffEvent{VmEvent: event},
  998. )
  999. case types.VirtualMachinePowerStateSuspended:
  1000. c.run.pause(c.VirtualMachine)
  1001. c.ctx.postEvent(
  1002. &types.VmSuspendingEvent{VmEvent: event},
  1003. &types.VmSuspendedEvent{VmEvent: event},
  1004. )
  1005. }
  1006. Map.Update(c.VirtualMachine, []types.PropertyChange{
  1007. {Name: "runtime.powerState", Val: c.state},
  1008. {Name: "summary.runtime.powerState", Val: c.state},
  1009. {Name: "summary.runtime.bootTime", Val: boot},
  1010. })
  1011. return nil, nil
  1012. }
  1013. func (vm *VirtualMachine) PowerOnVMTask(ctx *Context, c *types.PowerOnVM_Task) soap.HasFault {
  1014. if vm.Config.Template {
  1015. return &methods.PowerOnVM_TaskBody{
  1016. Fault_: Fault("cannot powerOn a template", &types.InvalidState{}),
  1017. }
  1018. }
  1019. runner := &powerVMTask{vm, types.VirtualMachinePowerStatePoweredOn, ctx}
  1020. task := CreateTask(runner.Reference(), "powerOn", runner.Run)
  1021. return &methods.PowerOnVM_TaskBody{
  1022. Res: &types.PowerOnVM_TaskResponse{
  1023. Returnval: task.Run(),
  1024. },
  1025. }
  1026. }
  1027. func (vm *VirtualMachine) PowerOffVMTask(ctx *Context, c *types.PowerOffVM_Task) soap.HasFault {
  1028. runner := &powerVMTask{vm, types.VirtualMachinePowerStatePoweredOff, ctx}
  1029. task := CreateTask(runner.Reference(), "powerOff", runner.Run)
  1030. return &methods.PowerOffVM_TaskBody{
  1031. Res: &types.PowerOffVM_TaskResponse{
  1032. Returnval: task.Run(),
  1033. },
  1034. }
  1035. }
  1036. func (vm *VirtualMachine) SuspendVMTask(ctx *Context, req *types.SuspendVM_Task) soap.HasFault {
  1037. runner := &powerVMTask{vm, types.VirtualMachinePowerStateSuspended, ctx}
  1038. task := CreateTask(runner.Reference(), "suspend", runner.Run)
  1039. return &methods.SuspendVM_TaskBody{
  1040. Res: &types.SuspendVM_TaskResponse{
  1041. Returnval: task.Run(),
  1042. },
  1043. }
  1044. }
  1045. func (vm *VirtualMachine) ResetVMTask(ctx *Context, req *types.ResetVM_Task) soap.HasFault {
  1046. task := CreateTask(vm, "reset", func(task *Task) (types.AnyType, types.BaseMethodFault) {
  1047. res := vm.PowerOffVMTask(ctx, &types.PowerOffVM_Task{This: vm.Self})
  1048. ctask := Map.Get(res.(*methods.PowerOffVM_TaskBody).Res.Returnval).(*Task)
  1049. if ctask.Info.Error != nil {
  1050. return nil, ctask.Info.Error.Fault
  1051. }
  1052. _ = vm.PowerOnVMTask(ctx, &types.PowerOnVM_Task{This: vm.Self})
  1053. return nil, nil
  1054. })
  1055. return &methods.ResetVM_TaskBody{
  1056. Res: &types.ResetVM_TaskResponse{
  1057. Returnval: task.Run(),
  1058. },
  1059. }
  1060. }
  1061. func (vm *VirtualMachine) ReconfigVMTask(ctx *Context, req *types.ReconfigVM_Task) soap.HasFault {
  1062. task := CreateTask(vm, "reconfigVm", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1063. err := vm.configure(&req.Spec)
  1064. if err != nil {
  1065. return nil, err
  1066. }
  1067. ctx.postEvent(&types.VmReconfiguredEvent{
  1068. VmEvent: vm.event(),
  1069. ConfigSpec: req.Spec,
  1070. })
  1071. return nil, nil
  1072. })
  1073. return &methods.ReconfigVM_TaskBody{
  1074. Res: &types.ReconfigVM_TaskResponse{
  1075. Returnval: task.Run(),
  1076. },
  1077. }
  1078. }
  1079. func (vm *VirtualMachine) UpgradeVMTask(req *types.UpgradeVM_Task) soap.HasFault {
  1080. body := &methods.UpgradeVM_TaskBody{}
  1081. task := CreateTask(vm, "upgradeVm", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1082. if vm.Config.Version != esx.HardwareVersion {
  1083. Map.Update(vm, []types.PropertyChange{{
  1084. Name: "config.version", Val: esx.HardwareVersion,
  1085. }})
  1086. }
  1087. return nil, nil
  1088. })
  1089. body.Res = &types.UpgradeVM_TaskResponse{
  1090. Returnval: task.Run(),
  1091. }
  1092. return body
  1093. }
  1094. func (vm *VirtualMachine) DestroyTask(ctx *Context, req *types.Destroy_Task) soap.HasFault {
  1095. task := CreateTask(vm, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1096. r := vm.UnregisterVM(ctx, &types.UnregisterVM{
  1097. This: req.This,
  1098. })
  1099. if r.Fault() != nil {
  1100. return nil, r.Fault().VimFault().(types.BaseMethodFault)
  1101. }
  1102. // Remove all devices
  1103. devices := object.VirtualDeviceList(vm.Config.Hardware.Device)
  1104. spec, _ := devices.ConfigSpec(types.VirtualDeviceConfigSpecOperationRemove)
  1105. vm.configureDevices(&types.VirtualMachineConfigSpec{DeviceChange: spec})
  1106. // Delete VM files from the datastore (ignoring result for now)
  1107. m := Map.FileManager()
  1108. dc := Map.getEntityDatacenter(vm).Reference()
  1109. _ = m.DeleteDatastoreFileTask(&types.DeleteDatastoreFile_Task{
  1110. This: m.Reference(),
  1111. Name: vm.Config.Files.LogDirectory,
  1112. Datacenter: &dc,
  1113. })
  1114. vm.run.remove(vm)
  1115. return nil, nil
  1116. })
  1117. return &methods.Destroy_TaskBody{
  1118. Res: &types.Destroy_TaskResponse{
  1119. Returnval: task.Run(),
  1120. },
  1121. }
  1122. }
  1123. func (vm *VirtualMachine) SetCustomValue(ctx *Context, req *types.SetCustomValue) soap.HasFault {
  1124. return SetCustomValue(ctx, req)
  1125. }
  1126. func (vm *VirtualMachine) UnregisterVM(ctx *Context, c *types.UnregisterVM) soap.HasFault {
  1127. r := &methods.UnregisterVMBody{}
  1128. if vm.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOn {
  1129. r.Fault_ = Fault("", &types.InvalidPowerState{
  1130. RequestedState: types.VirtualMachinePowerStatePoweredOff,
  1131. ExistingState: vm.Runtime.PowerState,
  1132. })
  1133. return r
  1134. }
  1135. host := Map.Get(*vm.Runtime.Host).(*HostSystem)
  1136. Map.RemoveReference(host, &host.Vm, vm.Self)
  1137. switch pool := Map.Get(*vm.ResourcePool).(type) {
  1138. case *ResourcePool:
  1139. Map.RemoveReference(pool, &pool.Vm, vm.Self)
  1140. case *VirtualApp:
  1141. Map.RemoveReference(pool, &pool.Vm, vm.Self)
  1142. }
  1143. for i := range vm.Datastore {
  1144. ds := Map.Get(vm.Datastore[i]).(*Datastore)
  1145. Map.RemoveReference(ds, &ds.Vm, vm.Self)
  1146. }
  1147. ctx.postEvent(&types.VmRemovedEvent{VmEvent: vm.event()})
  1148. Map.getEntityParent(vm, "Folder").(*Folder).removeChild(c.This)
  1149. r.Res = new(types.UnregisterVMResponse)
  1150. return r
  1151. }
  1152. func (vm *VirtualMachine) CloneVMTask(ctx *Context, req *types.CloneVM_Task) soap.HasFault {
  1153. ctx.Caller = &vm.Self
  1154. folder := Map.Get(req.Folder).(*Folder)
  1155. host := Map.Get(*vm.Runtime.Host).(*HostSystem)
  1156. event := vm.event()
  1157. ctx.postEvent(&types.VmBeingClonedEvent{
  1158. VmCloneEvent: types.VmCloneEvent{
  1159. VmEvent: event,
  1160. },
  1161. DestFolder: folder.eventArgument(),
  1162. DestName: req.Name,
  1163. DestHost: *host.eventArgument(),
  1164. })
  1165. task := CreateTask(vm, "cloneVm", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1166. config := types.VirtualMachineConfigSpec{
  1167. Name: req.Name,
  1168. GuestId: vm.Config.GuestId,
  1169. Files: &types.VirtualMachineFileInfo{
  1170. VmPathName: strings.Replace(vm.Config.Files.VmPathName, vm.Name, req.Name, -1),
  1171. },
  1172. }
  1173. defaultDevices := object.VirtualDeviceList(esx.VirtualDevice)
  1174. devices := vm.Config.Hardware.Device
  1175. for _, device := range devices {
  1176. var fop types.VirtualDeviceConfigSpecFileOperation
  1177. if defaultDevices.Find(object.VirtualDeviceList(devices).Name(device)) != nil {
  1178. // Default devices are added during CreateVMTask
  1179. continue
  1180. }
  1181. switch disk := device.(type) {
  1182. case *types.VirtualDisk:
  1183. // TODO: consider VirtualMachineCloneSpec.DiskMoveType
  1184. fop = types.VirtualDeviceConfigSpecFileOperationCreate
  1185. // Leave FileName empty so CreateVM will just create a new one under VmPathName
  1186. disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo).FileName = ""
  1187. disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo).Parent = nil
  1188. }
  1189. config.DeviceChange = append(config.DeviceChange, &types.VirtualDeviceConfigSpec{
  1190. Operation: types.VirtualDeviceConfigSpecOperationAdd,
  1191. Device: device,
  1192. FileOperation: fop,
  1193. })
  1194. }
  1195. res := folder.CreateVMTask(ctx, &types.CreateVM_Task{
  1196. This: folder.Self,
  1197. Config: config,
  1198. Pool: *vm.ResourcePool,
  1199. Host: vm.Runtime.Host,
  1200. })
  1201. ctask := Map.Get(res.(*methods.CreateVM_TaskBody).Res.Returnval).(*Task)
  1202. if ctask.Info.Error != nil {
  1203. return nil, ctask.Info.Error.Fault
  1204. }
  1205. ref := ctask.Info.Result.(types.ManagedObjectReference)
  1206. clone := Map.Get(ref).(*VirtualMachine)
  1207. clone.configureDevices(&types.VirtualMachineConfigSpec{DeviceChange: req.Spec.Location.DeviceChange})
  1208. if req.Spec.Config != nil && req.Spec.Config.DeviceChange != nil {
  1209. clone.configureDevices(&types.VirtualMachineConfigSpec{DeviceChange: req.Spec.Config.DeviceChange})
  1210. }
  1211. ctx.postEvent(&types.VmClonedEvent{
  1212. VmCloneEvent: types.VmCloneEvent{VmEvent: clone.event()},
  1213. SourceVm: *event.Vm,
  1214. })
  1215. return ref, nil
  1216. })
  1217. return &methods.CloneVM_TaskBody{
  1218. Res: &types.CloneVM_TaskResponse{
  1219. Returnval: task.Run(),
  1220. },
  1221. }
  1222. }
  1223. func (vm *VirtualMachine) RelocateVMTask(req *types.RelocateVM_Task) soap.HasFault {
  1224. task := CreateTask(vm, "relocateVm", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1225. var changes []types.PropertyChange
  1226. if ref := req.Spec.Datastore; ref != nil {
  1227. ds := Map.Get(*ref).(*Datastore)
  1228. Map.RemoveReference(ds, &ds.Vm, *ref)
  1229. // TODO: migrate vm.Config.Files, vm.Summary.Config.VmPathName, vm.Layout and vm.LayoutEx
  1230. changes = append(changes, types.PropertyChange{Name: "datastore", Val: []types.ManagedObjectReference{*ref}})
  1231. }
  1232. if ref := req.Spec.Pool; ref != nil {
  1233. pool := Map.Get(*ref).(*ResourcePool)
  1234. Map.RemoveReference(pool, &pool.Vm, *ref)
  1235. changes = append(changes, types.PropertyChange{Name: "resourcePool", Val: ref})
  1236. }
  1237. if ref := req.Spec.Host; ref != nil {
  1238. host := Map.Get(*ref).(*HostSystem)
  1239. Map.RemoveReference(host, &host.Vm, *ref)
  1240. changes = append(changes,
  1241. types.PropertyChange{Name: "runtime.host", Val: ref},
  1242. types.PropertyChange{Name: "summary.runtime.host", Val: ref},
  1243. )
  1244. }
  1245. Map.Update(vm, changes)
  1246. return nil, nil
  1247. })
  1248. return &methods.RelocateVM_TaskBody{
  1249. Res: &types.RelocateVM_TaskResponse{
  1250. Returnval: task.Run(),
  1251. },
  1252. }
  1253. }
  1254. func (vm *VirtualMachine) CreateSnapshotTask(req *types.CreateSnapshot_Task) soap.HasFault {
  1255. task := CreateTask(vm, "createSnapshot", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1256. var changes []types.PropertyChange
  1257. if vm.Snapshot == nil {
  1258. vm.Snapshot = &types.VirtualMachineSnapshotInfo{}
  1259. }
  1260. snapshot := &VirtualMachineSnapshot{}
  1261. snapshot.Vm = vm.Reference()
  1262. snapshot.Config = *vm.Config
  1263. Map.Put(snapshot)
  1264. treeItem := types.VirtualMachineSnapshotTree{
  1265. Snapshot: snapshot.Self,
  1266. Vm: snapshot.Vm,
  1267. Name: req.Name,
  1268. Description: req.Description,
  1269. Id: atomic.AddInt32(&vm.sid, 1),
  1270. CreateTime: time.Now(),
  1271. State: vm.Runtime.PowerState,
  1272. Quiesced: req.Quiesce,
  1273. BackupManifest: "",
  1274. ReplaySupported: types.NewBool(false),
  1275. }
  1276. cur := vm.Snapshot.CurrentSnapshot
  1277. if cur != nil {
  1278. parent := Map.Get(*cur).(*VirtualMachineSnapshot)
  1279. parent.ChildSnapshot = append(parent.ChildSnapshot, snapshot.Self)
  1280. ss := findSnapshotInTree(vm.Snapshot.RootSnapshotList, *cur)
  1281. ss.ChildSnapshotList = append(ss.ChildSnapshotList, treeItem)
  1282. } else {
  1283. changes = append(changes, types.PropertyChange{
  1284. Name: "snapshot.rootSnapshotList",
  1285. Val: append(vm.Snapshot.RootSnapshotList, treeItem),
  1286. })
  1287. }
  1288. snapshot.createSnapshotFiles()
  1289. changes = append(changes, types.PropertyChange{Name: "snapshot.currentSnapshot", Val: snapshot.Self})
  1290. Map.Update(vm, changes)
  1291. return nil, nil
  1292. })
  1293. return &methods.CreateSnapshot_TaskBody{
  1294. Res: &types.CreateSnapshot_TaskResponse{
  1295. Returnval: task.Run(),
  1296. },
  1297. }
  1298. }
  1299. func (vm *VirtualMachine) RevertToCurrentSnapshotTask(req *types.RevertToCurrentSnapshot_Task) soap.HasFault {
  1300. body := &methods.RevertToCurrentSnapshot_TaskBody{}
  1301. if vm.Snapshot == nil || vm.Snapshot.CurrentSnapshot == nil {
  1302. body.Fault_ = Fault("snapshot not found", &types.NotFound{})
  1303. return body
  1304. }
  1305. task := CreateTask(vm, "revertSnapshot", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1306. return nil, nil
  1307. })
  1308. body.Res = &types.RevertToCurrentSnapshot_TaskResponse{
  1309. Returnval: task.Run(),
  1310. }
  1311. return body
  1312. }
  1313. func (vm *VirtualMachine) RemoveAllSnapshotsTask(ctx *Context, req *types.RemoveAllSnapshots_Task) soap.HasFault {
  1314. task := CreateTask(vm, "RemoveAllSnapshots", func(t *Task) (types.AnyType, types.BaseMethodFault) {
  1315. if vm.Snapshot == nil {
  1316. return nil, nil
  1317. }
  1318. refs := allSnapshotsInTree(vm.Snapshot.RootSnapshotList)
  1319. Map.Update(vm, []types.PropertyChange{
  1320. {Name: "snapshot", Val: nil},
  1321. })
  1322. for _, ref := range refs {
  1323. Map.Get(ref).(*VirtualMachineSnapshot).removeSnapshotFiles(ctx)
  1324. Map.Remove(ref)
  1325. }
  1326. return nil, nil
  1327. })
  1328. return &methods.RemoveAllSnapshots_TaskBody{
  1329. Res: &types.RemoveAllSnapshots_TaskResponse{
  1330. Returnval: task.Run(),
  1331. },
  1332. }
  1333. }
  1334. func (vm *VirtualMachine) ShutdownGuest(ctx *Context, c *types.ShutdownGuest) soap.HasFault {
  1335. r := &methods.ShutdownGuestBody{}
  1336. // should be poweron
  1337. if vm.Runtime.PowerState == types.VirtualMachinePowerStatePoweredOff {
  1338. r.Fault_ = Fault("", &types.InvalidPowerState{
  1339. RequestedState: types.VirtualMachinePowerStatePoweredOn,
  1340. ExistingState: vm.Runtime.PowerState,
  1341. })
  1342. return r
  1343. }
  1344. // change state
  1345. vm.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff
  1346. vm.Summary.Runtime.PowerState = types.VirtualMachinePowerStatePoweredOff
  1347. event := vm.event()
  1348. ctx.postEvent(
  1349. &types.VmGuestShutdownEvent{VmEvent: event},
  1350. &types.VmPoweredOffEvent{VmEvent: event},
  1351. )
  1352. vm.run.stop(vm)
  1353. Map.Update(vm, []types.PropertyChange{
  1354. {Name: "runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff},
  1355. {Name: "summary.runtime.powerState", Val: types.VirtualMachinePowerStatePoweredOff},
  1356. })
  1357. r.Res = new(types.ShutdownGuestResponse)
  1358. return r
  1359. }
  1360. func (vm *VirtualMachine) MarkAsTemplate(req *types.MarkAsTemplate) soap.HasFault {
  1361. r := &methods.MarkAsTemplateBody{}
  1362. if vm.Runtime.PowerState != types.VirtualMachinePowerStatePoweredOff {
  1363. r.Fault_ = Fault("", &types.InvalidPowerState{
  1364. RequestedState: types.VirtualMachinePowerStatePoweredOff,
  1365. ExistingState: vm.Runtime.PowerState,
  1366. })
  1367. return r
  1368. }
  1369. vm.Config.Template = true
  1370. r.Res = &types.MarkAsTemplateResponse{}
  1371. return r
  1372. }
  1373. func findSnapshotInTree(tree []types.VirtualMachineSnapshotTree, ref types.ManagedObjectReference) *types.VirtualMachineSnapshotTree {
  1374. if tree == nil {
  1375. return nil
  1376. }
  1377. for i, ss := range tree {
  1378. if ss.Snapshot == ref {
  1379. return &tree[i]
  1380. }
  1381. target := findSnapshotInTree(ss.ChildSnapshotList, ref)
  1382. if target != nil {
  1383. return target
  1384. }
  1385. }
  1386. return nil
  1387. }
  1388. func findParentSnapshot(tree types.VirtualMachineSnapshotTree, ref types.ManagedObjectReference) *types.ManagedObjectReference {
  1389. for _, ss := range tree.ChildSnapshotList {
  1390. if ss.Snapshot == ref {
  1391. return &tree.Snapshot
  1392. }
  1393. res := findParentSnapshot(ss, ref)
  1394. if res != nil {
  1395. return res
  1396. }
  1397. }
  1398. return nil
  1399. }
  1400. func findParentSnapshotInTree(tree []types.VirtualMachineSnapshotTree, ref types.ManagedObjectReference) *types.ManagedObjectReference {
  1401. if tree == nil {
  1402. return nil
  1403. }
  1404. for _, ss := range tree {
  1405. res := findParentSnapshot(ss, ref)
  1406. if res != nil {
  1407. return res
  1408. }
  1409. }
  1410. return nil
  1411. }
  1412. func removeSnapshotInTree(tree []types.VirtualMachineSnapshotTree, ref types.ManagedObjectReference, removeChildren bool) []types.VirtualMachineSnapshotTree {
  1413. if tree == nil {
  1414. return tree
  1415. }
  1416. var result []types.VirtualMachineSnapshotTree
  1417. for _, ss := range tree {
  1418. if ss.Snapshot == ref {
  1419. if !removeChildren {
  1420. result = append(result, ss.ChildSnapshotList...)
  1421. }
  1422. } else {
  1423. ss.ChildSnapshotList = removeSnapshotInTree(ss.ChildSnapshotList, ref, removeChildren)
  1424. result = append(result, ss)
  1425. }
  1426. }
  1427. return result
  1428. }
  1429. func allSnapshotsInTree(tree []types.VirtualMachineSnapshotTree) []types.ManagedObjectReference {
  1430. var result []types.ManagedObjectReference
  1431. if tree == nil {
  1432. return result
  1433. }
  1434. for _, ss := range tree {
  1435. result = append(result, ss.Snapshot)
  1436. result = append(result, allSnapshotsInTree(ss.ChildSnapshotList)...)
  1437. }
  1438. return result
  1439. }