finder.go 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049
  1. /*
  2. Copyright (c) 2014-2017 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 find
  14. import (
  15. "context"
  16. "errors"
  17. "path"
  18. "strings"
  19. "github.com/vmware/govmomi/list"
  20. "github.com/vmware/govmomi/object"
  21. "github.com/vmware/govmomi/property"
  22. "github.com/vmware/govmomi/vim25"
  23. "github.com/vmware/govmomi/vim25/mo"
  24. "github.com/vmware/govmomi/vim25/types"
  25. )
  26. type Finder struct {
  27. client *vim25.Client
  28. r recurser
  29. dc *object.Datacenter
  30. si *object.SearchIndex
  31. folders *object.DatacenterFolders
  32. }
  33. func NewFinder(client *vim25.Client, all bool) *Finder {
  34. f := &Finder{
  35. client: client,
  36. si: object.NewSearchIndex(client),
  37. r: recurser{
  38. Collector: property.DefaultCollector(client),
  39. All: all,
  40. },
  41. }
  42. return f
  43. }
  44. func (f *Finder) SetDatacenter(dc *object.Datacenter) *Finder {
  45. f.dc = dc
  46. f.folders = nil
  47. return f
  48. }
  49. // findRoot makes it possible to use "find" mode with a different root path.
  50. // Example: ResourcePoolList("/dc1/host/cluster1/...")
  51. func (f *Finder) findRoot(ctx context.Context, root *list.Element, parts []string) bool {
  52. if len(parts) == 0 {
  53. return false
  54. }
  55. ix := len(parts) - 1
  56. if parts[ix] != "..." {
  57. return false
  58. }
  59. if ix == 0 {
  60. return true // We already have the Object for root.Path
  61. }
  62. // Lookup the Object for the new root.Path
  63. rootPath := path.Join(root.Path, path.Join(parts[:ix]...))
  64. ref, err := f.si.FindByInventoryPath(ctx, rootPath)
  65. if err != nil || ref == nil {
  66. // If we get an error or fail to match, fall through to find() with the original root and path
  67. return false
  68. }
  69. root.Path = rootPath
  70. root.Object = ref
  71. return true
  72. }
  73. func (f *Finder) find(ctx context.Context, arg string, s *spec) ([]list.Element, error) {
  74. isPath := strings.Contains(arg, "/")
  75. root := list.Element{
  76. Path: "/",
  77. Object: object.NewRootFolder(f.client),
  78. }
  79. parts := list.ToParts(arg)
  80. if len(parts) > 0 {
  81. switch parts[0] {
  82. case "..": // Not supported; many edge case, little value
  83. return nil, errors.New("cannot traverse up a tree")
  84. case ".": // Relative to whatever
  85. pivot, err := s.Relative(ctx)
  86. if err != nil {
  87. return nil, err
  88. }
  89. mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, pivot.Reference())
  90. if err != nil {
  91. return nil, err
  92. }
  93. for _, me := range mes {
  94. // Skip root entity in building inventory path.
  95. if me.Parent == nil {
  96. continue
  97. }
  98. root.Path = path.Join(root.Path, me.Name)
  99. }
  100. root.Object = pivot
  101. parts = parts[1:]
  102. }
  103. }
  104. if s.listMode(isPath) {
  105. if f.findRoot(ctx, &root, parts) {
  106. parts = []string{"*"}
  107. } else {
  108. return f.r.List(ctx, s, root, parts)
  109. }
  110. }
  111. s.Parents = append(s.Parents, s.Nested...)
  112. return f.r.Find(ctx, s, root, parts)
  113. }
  114. func (f *Finder) datacenter() (*object.Datacenter, error) {
  115. if f.dc == nil {
  116. return nil, errors.New("please specify a datacenter")
  117. }
  118. return f.dc, nil
  119. }
  120. // datacenterPath returns the absolute path to the Datacenter containing the given ref
  121. func (f *Finder) datacenterPath(ctx context.Context, ref types.ManagedObjectReference) (string, error) {
  122. mes, err := mo.Ancestors(ctx, f.client, f.client.ServiceContent.PropertyCollector, ref)
  123. if err != nil {
  124. return "", err
  125. }
  126. // Chop leaves under the Datacenter
  127. for i := len(mes) - 1; i > 0; i-- {
  128. if mes[i].Self.Type == "Datacenter" {
  129. break
  130. }
  131. mes = mes[:i]
  132. }
  133. var p string
  134. for _, me := range mes {
  135. // Skip root entity in building inventory path.
  136. if me.Parent == nil {
  137. continue
  138. }
  139. p = p + "/" + me.Name
  140. }
  141. return p, nil
  142. }
  143. func (f *Finder) dcFolders(ctx context.Context) (*object.DatacenterFolders, error) {
  144. if f.folders != nil {
  145. return f.folders, nil
  146. }
  147. dc, err := f.datacenter()
  148. if err != nil {
  149. return nil, err
  150. }
  151. folders, err := dc.Folders(ctx)
  152. if err != nil {
  153. return nil, err
  154. }
  155. f.folders = folders
  156. return f.folders, nil
  157. }
  158. func (f *Finder) dcReference(_ context.Context) (object.Reference, error) {
  159. dc, err := f.datacenter()
  160. if err != nil {
  161. return nil, err
  162. }
  163. return dc, nil
  164. }
  165. func (f *Finder) vmFolder(ctx context.Context) (object.Reference, error) {
  166. folders, err := f.dcFolders(ctx)
  167. if err != nil {
  168. return nil, err
  169. }
  170. return folders.VmFolder, nil
  171. }
  172. func (f *Finder) hostFolder(ctx context.Context) (object.Reference, error) {
  173. folders, err := f.dcFolders(ctx)
  174. if err != nil {
  175. return nil, err
  176. }
  177. return folders.HostFolder, nil
  178. }
  179. func (f *Finder) datastoreFolder(ctx context.Context) (object.Reference, error) {
  180. folders, err := f.dcFolders(ctx)
  181. if err != nil {
  182. return nil, err
  183. }
  184. return folders.DatastoreFolder, nil
  185. }
  186. func (f *Finder) networkFolder(ctx context.Context) (object.Reference, error) {
  187. folders, err := f.dcFolders(ctx)
  188. if err != nil {
  189. return nil, err
  190. }
  191. return folders.NetworkFolder, nil
  192. }
  193. func (f *Finder) rootFolder(_ context.Context) (object.Reference, error) {
  194. return object.NewRootFolder(f.client), nil
  195. }
  196. func (f *Finder) managedObjectList(ctx context.Context, path string, tl bool, include []string) ([]list.Element, error) {
  197. fn := f.rootFolder
  198. if f.dc != nil {
  199. fn = f.dcReference
  200. }
  201. if len(path) == 0 {
  202. path = "."
  203. }
  204. s := &spec{
  205. Relative: fn,
  206. Parents: []string{"ComputeResource", "ClusterComputeResource", "HostSystem", "VirtualApp", "StoragePod"},
  207. Include: include,
  208. }
  209. if tl {
  210. s.Contents = true
  211. s.ListMode = types.NewBool(true)
  212. }
  213. return f.find(ctx, path, s)
  214. }
  215. // Element returns an Element for the given ManagedObjectReference
  216. // This method is only useful for looking up the InventoryPath of a ManagedObjectReference.
  217. func (f *Finder) Element(ctx context.Context, ref types.ManagedObjectReference) (*list.Element, error) {
  218. rl := func(_ context.Context) (object.Reference, error) {
  219. return ref, nil
  220. }
  221. s := &spec{
  222. Relative: rl,
  223. }
  224. e, err := f.find(ctx, "./", s)
  225. if err != nil {
  226. return nil, err
  227. }
  228. if len(e) == 0 {
  229. return nil, &NotFoundError{ref.Type, ref.Value}
  230. }
  231. if len(e) > 1 {
  232. panic("ManagedObjectReference must be unique")
  233. }
  234. return &e[0], nil
  235. }
  236. // ObjectReference converts the given ManagedObjectReference to a type from the object package via object.NewReference
  237. // with the object.Common.InventoryPath field set.
  238. func (f *Finder) ObjectReference(ctx context.Context, ref types.ManagedObjectReference) (object.Reference, error) {
  239. e, err := f.Element(ctx, ref)
  240. if err != nil {
  241. return nil, err
  242. }
  243. r := object.NewReference(f.client, ref)
  244. type common interface {
  245. SetInventoryPath(string)
  246. }
  247. r.(common).SetInventoryPath(e.Path)
  248. if f.dc != nil {
  249. if ds, ok := r.(*object.Datastore); ok {
  250. ds.DatacenterPath = f.dc.InventoryPath
  251. }
  252. }
  253. return r, nil
  254. }
  255. func (f *Finder) ManagedObjectList(ctx context.Context, path string, include ...string) ([]list.Element, error) {
  256. return f.managedObjectList(ctx, path, false, include)
  257. }
  258. func (f *Finder) ManagedObjectListChildren(ctx context.Context, path string, include ...string) ([]list.Element, error) {
  259. return f.managedObjectList(ctx, path, true, include)
  260. }
  261. func (f *Finder) DatacenterList(ctx context.Context, path string) ([]*object.Datacenter, error) {
  262. s := &spec{
  263. Relative: f.rootFolder,
  264. Include: []string{"Datacenter"},
  265. }
  266. es, err := f.find(ctx, path, s)
  267. if err != nil {
  268. return nil, err
  269. }
  270. var dcs []*object.Datacenter
  271. for _, e := range es {
  272. ref := e.Object.Reference()
  273. if ref.Type == "Datacenter" {
  274. dc := object.NewDatacenter(f.client, ref)
  275. dc.InventoryPath = e.Path
  276. dcs = append(dcs, dc)
  277. }
  278. }
  279. if len(dcs) == 0 {
  280. return nil, &NotFoundError{"datacenter", path}
  281. }
  282. return dcs, nil
  283. }
  284. func (f *Finder) Datacenter(ctx context.Context, path string) (*object.Datacenter, error) {
  285. dcs, err := f.DatacenterList(ctx, path)
  286. if err != nil {
  287. return nil, err
  288. }
  289. if len(dcs) > 1 {
  290. return nil, &MultipleFoundError{"datacenter", path}
  291. }
  292. return dcs[0], nil
  293. }
  294. func (f *Finder) DefaultDatacenter(ctx context.Context) (*object.Datacenter, error) {
  295. dc, err := f.Datacenter(ctx, "*")
  296. if err != nil {
  297. return nil, toDefaultError(err)
  298. }
  299. return dc, nil
  300. }
  301. func (f *Finder) DatacenterOrDefault(ctx context.Context, path string) (*object.Datacenter, error) {
  302. if path != "" {
  303. dc, err := f.Datacenter(ctx, path)
  304. if err != nil {
  305. return nil, err
  306. }
  307. return dc, nil
  308. }
  309. return f.DefaultDatacenter(ctx)
  310. }
  311. func (f *Finder) DatastoreList(ctx context.Context, path string) ([]*object.Datastore, error) {
  312. s := &spec{
  313. Relative: f.datastoreFolder,
  314. Parents: []string{"StoragePod"},
  315. }
  316. es, err := f.find(ctx, path, s)
  317. if err != nil {
  318. return nil, err
  319. }
  320. var dss []*object.Datastore
  321. for _, e := range es {
  322. ref := e.Object.Reference()
  323. if ref.Type == "Datastore" {
  324. ds := object.NewDatastore(f.client, ref)
  325. ds.InventoryPath = e.Path
  326. if f.dc == nil {
  327. // In this case SetDatacenter was not called and path is absolute
  328. ds.DatacenterPath, err = f.datacenterPath(ctx, ref)
  329. if err != nil {
  330. return nil, err
  331. }
  332. } else {
  333. ds.DatacenterPath = f.dc.InventoryPath
  334. }
  335. dss = append(dss, ds)
  336. }
  337. }
  338. if len(dss) == 0 {
  339. return nil, &NotFoundError{"datastore", path}
  340. }
  341. return dss, nil
  342. }
  343. func (f *Finder) Datastore(ctx context.Context, path string) (*object.Datastore, error) {
  344. dss, err := f.DatastoreList(ctx, path)
  345. if err != nil {
  346. return nil, err
  347. }
  348. if len(dss) > 1 {
  349. return nil, &MultipleFoundError{"datastore", path}
  350. }
  351. return dss[0], nil
  352. }
  353. func (f *Finder) DefaultDatastore(ctx context.Context) (*object.Datastore, error) {
  354. ds, err := f.Datastore(ctx, "*")
  355. if err != nil {
  356. return nil, toDefaultError(err)
  357. }
  358. return ds, nil
  359. }
  360. func (f *Finder) DatastoreOrDefault(ctx context.Context, path string) (*object.Datastore, error) {
  361. if path != "" {
  362. ds, err := f.Datastore(ctx, path)
  363. if err != nil {
  364. return nil, err
  365. }
  366. return ds, nil
  367. }
  368. return f.DefaultDatastore(ctx)
  369. }
  370. func (f *Finder) DatastoreClusterList(ctx context.Context, path string) ([]*object.StoragePod, error) {
  371. s := &spec{
  372. Relative: f.datastoreFolder,
  373. }
  374. es, err := f.find(ctx, path, s)
  375. if err != nil {
  376. return nil, err
  377. }
  378. var sps []*object.StoragePod
  379. for _, e := range es {
  380. ref := e.Object.Reference()
  381. if ref.Type == "StoragePod" {
  382. sp := object.NewStoragePod(f.client, ref)
  383. sp.InventoryPath = e.Path
  384. sps = append(sps, sp)
  385. }
  386. }
  387. if len(sps) == 0 {
  388. return nil, &NotFoundError{"datastore cluster", path}
  389. }
  390. return sps, nil
  391. }
  392. func (f *Finder) DatastoreCluster(ctx context.Context, path string) (*object.StoragePod, error) {
  393. sps, err := f.DatastoreClusterList(ctx, path)
  394. if err != nil {
  395. return nil, err
  396. }
  397. if len(sps) > 1 {
  398. return nil, &MultipleFoundError{"datastore cluster", path}
  399. }
  400. return sps[0], nil
  401. }
  402. func (f *Finder) DefaultDatastoreCluster(ctx context.Context) (*object.StoragePod, error) {
  403. sp, err := f.DatastoreCluster(ctx, "*")
  404. if err != nil {
  405. return nil, toDefaultError(err)
  406. }
  407. return sp, nil
  408. }
  409. func (f *Finder) DatastoreClusterOrDefault(ctx context.Context, path string) (*object.StoragePod, error) {
  410. if path != "" {
  411. sp, err := f.DatastoreCluster(ctx, path)
  412. if err != nil {
  413. return nil, err
  414. }
  415. return sp, nil
  416. }
  417. return f.DefaultDatastoreCluster(ctx)
  418. }
  419. func (f *Finder) ComputeResourceList(ctx context.Context, path string) ([]*object.ComputeResource, error) {
  420. s := &spec{
  421. Relative: f.hostFolder,
  422. }
  423. es, err := f.find(ctx, path, s)
  424. if err != nil {
  425. return nil, err
  426. }
  427. var crs []*object.ComputeResource
  428. for _, e := range es {
  429. var cr *object.ComputeResource
  430. switch o := e.Object.(type) {
  431. case mo.ComputeResource, mo.ClusterComputeResource:
  432. cr = object.NewComputeResource(f.client, o.Reference())
  433. default:
  434. continue
  435. }
  436. cr.InventoryPath = e.Path
  437. crs = append(crs, cr)
  438. }
  439. if len(crs) == 0 {
  440. return nil, &NotFoundError{"compute resource", path}
  441. }
  442. return crs, nil
  443. }
  444. func (f *Finder) ComputeResource(ctx context.Context, path string) (*object.ComputeResource, error) {
  445. crs, err := f.ComputeResourceList(ctx, path)
  446. if err != nil {
  447. return nil, err
  448. }
  449. if len(crs) > 1 {
  450. return nil, &MultipleFoundError{"compute resource", path}
  451. }
  452. return crs[0], nil
  453. }
  454. func (f *Finder) DefaultComputeResource(ctx context.Context) (*object.ComputeResource, error) {
  455. cr, err := f.ComputeResource(ctx, "*")
  456. if err != nil {
  457. return nil, toDefaultError(err)
  458. }
  459. return cr, nil
  460. }
  461. func (f *Finder) ComputeResourceOrDefault(ctx context.Context, path string) (*object.ComputeResource, error) {
  462. if path != "" {
  463. cr, err := f.ComputeResource(ctx, path)
  464. if err != nil {
  465. return nil, err
  466. }
  467. return cr, nil
  468. }
  469. return f.DefaultComputeResource(ctx)
  470. }
  471. func (f *Finder) ClusterComputeResourceList(ctx context.Context, path string) ([]*object.ClusterComputeResource, error) {
  472. s := &spec{
  473. Relative: f.hostFolder,
  474. }
  475. es, err := f.find(ctx, path, s)
  476. if err != nil {
  477. return nil, err
  478. }
  479. var ccrs []*object.ClusterComputeResource
  480. for _, e := range es {
  481. var ccr *object.ClusterComputeResource
  482. switch o := e.Object.(type) {
  483. case mo.ClusterComputeResource:
  484. ccr = object.NewClusterComputeResource(f.client, o.Reference())
  485. default:
  486. continue
  487. }
  488. ccr.InventoryPath = e.Path
  489. ccrs = append(ccrs, ccr)
  490. }
  491. if len(ccrs) == 0 {
  492. return nil, &NotFoundError{"cluster", path}
  493. }
  494. return ccrs, nil
  495. }
  496. func (f *Finder) DefaultClusterComputeResource(ctx context.Context) (*object.ClusterComputeResource, error) {
  497. cr, err := f.ClusterComputeResource(ctx, "*")
  498. if err != nil {
  499. return nil, toDefaultError(err)
  500. }
  501. return cr, nil
  502. }
  503. func (f *Finder) ClusterComputeResource(ctx context.Context, path string) (*object.ClusterComputeResource, error) {
  504. ccrs, err := f.ClusterComputeResourceList(ctx, path)
  505. if err != nil {
  506. return nil, err
  507. }
  508. if len(ccrs) > 1 {
  509. return nil, &MultipleFoundError{"cluster", path}
  510. }
  511. return ccrs[0], nil
  512. }
  513. func (f *Finder) ClusterComputeResourceOrDefault(ctx context.Context, path string) (*object.ClusterComputeResource, error) {
  514. if path != "" {
  515. cr, err := f.ClusterComputeResource(ctx, path)
  516. if err != nil {
  517. return nil, err
  518. }
  519. return cr, nil
  520. }
  521. return f.DefaultClusterComputeResource(ctx)
  522. }
  523. func (f *Finder) HostSystemList(ctx context.Context, path string) ([]*object.HostSystem, error) {
  524. s := &spec{
  525. Relative: f.hostFolder,
  526. Parents: []string{"ComputeResource", "ClusterComputeResource"},
  527. Include: []string{"HostSystem"},
  528. }
  529. es, err := f.find(ctx, path, s)
  530. if err != nil {
  531. return nil, err
  532. }
  533. var hss []*object.HostSystem
  534. for _, e := range es {
  535. var hs *object.HostSystem
  536. switch o := e.Object.(type) {
  537. case mo.HostSystem:
  538. hs = object.NewHostSystem(f.client, o.Reference())
  539. hs.InventoryPath = e.Path
  540. hss = append(hss, hs)
  541. case mo.ComputeResource, mo.ClusterComputeResource:
  542. cr := object.NewComputeResource(f.client, o.Reference())
  543. cr.InventoryPath = e.Path
  544. hosts, err := cr.Hosts(ctx)
  545. if err != nil {
  546. return nil, err
  547. }
  548. hss = append(hss, hosts...)
  549. }
  550. }
  551. if len(hss) == 0 {
  552. return nil, &NotFoundError{"host", path}
  553. }
  554. return hss, nil
  555. }
  556. func (f *Finder) HostSystem(ctx context.Context, path string) (*object.HostSystem, error) {
  557. hss, err := f.HostSystemList(ctx, path)
  558. if err != nil {
  559. return nil, err
  560. }
  561. if len(hss) > 1 {
  562. return nil, &MultipleFoundError{"host", path}
  563. }
  564. return hss[0], nil
  565. }
  566. func (f *Finder) DefaultHostSystem(ctx context.Context) (*object.HostSystem, error) {
  567. hs, err := f.HostSystem(ctx, "*")
  568. if err != nil {
  569. return nil, toDefaultError(err)
  570. }
  571. return hs, nil
  572. }
  573. func (f *Finder) HostSystemOrDefault(ctx context.Context, path string) (*object.HostSystem, error) {
  574. if path != "" {
  575. hs, err := f.HostSystem(ctx, path)
  576. if err != nil {
  577. return nil, err
  578. }
  579. return hs, nil
  580. }
  581. return f.DefaultHostSystem(ctx)
  582. }
  583. func (f *Finder) NetworkList(ctx context.Context, path string) ([]object.NetworkReference, error) {
  584. s := &spec{
  585. Relative: f.networkFolder,
  586. }
  587. es, err := f.find(ctx, path, s)
  588. if err != nil {
  589. return nil, err
  590. }
  591. var ns []object.NetworkReference
  592. for _, e := range es {
  593. ref := e.Object.Reference()
  594. switch ref.Type {
  595. case "Network":
  596. r := object.NewNetwork(f.client, ref)
  597. r.InventoryPath = e.Path
  598. ns = append(ns, r)
  599. case "OpaqueNetwork":
  600. r := object.NewOpaqueNetwork(f.client, ref)
  601. r.InventoryPath = e.Path
  602. ns = append(ns, r)
  603. case "DistributedVirtualPortgroup":
  604. r := object.NewDistributedVirtualPortgroup(f.client, ref)
  605. r.InventoryPath = e.Path
  606. ns = append(ns, r)
  607. case "DistributedVirtualSwitch", "VmwareDistributedVirtualSwitch":
  608. r := object.NewDistributedVirtualSwitch(f.client, ref)
  609. r.InventoryPath = e.Path
  610. ns = append(ns, r)
  611. }
  612. }
  613. if len(ns) == 0 {
  614. return nil, &NotFoundError{"network", path}
  615. }
  616. return ns, nil
  617. }
  618. func (f *Finder) Network(ctx context.Context, path string) (object.NetworkReference, error) {
  619. networks, err := f.NetworkList(ctx, path)
  620. if err != nil {
  621. return nil, err
  622. }
  623. if len(networks) > 1 {
  624. return nil, &MultipleFoundError{"network", path}
  625. }
  626. return networks[0], nil
  627. }
  628. func (f *Finder) DefaultNetwork(ctx context.Context) (object.NetworkReference, error) {
  629. network, err := f.Network(ctx, "*")
  630. if err != nil {
  631. return nil, toDefaultError(err)
  632. }
  633. return network, nil
  634. }
  635. func (f *Finder) NetworkOrDefault(ctx context.Context, path string) (object.NetworkReference, error) {
  636. if path != "" {
  637. network, err := f.Network(ctx, path)
  638. if err != nil {
  639. return nil, err
  640. }
  641. return network, nil
  642. }
  643. return f.DefaultNetwork(ctx)
  644. }
  645. func (f *Finder) ResourcePoolList(ctx context.Context, path string) ([]*object.ResourcePool, error) {
  646. s := &spec{
  647. Relative: f.hostFolder,
  648. Parents: []string{"ComputeResource", "ClusterComputeResource", "VirtualApp"},
  649. Nested: []string{"ResourcePool"},
  650. Contents: true,
  651. }
  652. es, err := f.find(ctx, path, s)
  653. if err != nil {
  654. return nil, err
  655. }
  656. var rps []*object.ResourcePool
  657. for _, e := range es {
  658. var rp *object.ResourcePool
  659. switch o := e.Object.(type) {
  660. case mo.ResourcePool:
  661. rp = object.NewResourcePool(f.client, o.Reference())
  662. rp.InventoryPath = e.Path
  663. rps = append(rps, rp)
  664. }
  665. }
  666. if len(rps) == 0 {
  667. return nil, &NotFoundError{"resource pool", path}
  668. }
  669. return rps, nil
  670. }
  671. func (f *Finder) ResourcePool(ctx context.Context, path string) (*object.ResourcePool, error) {
  672. rps, err := f.ResourcePoolList(ctx, path)
  673. if err != nil {
  674. return nil, err
  675. }
  676. if len(rps) > 1 {
  677. return nil, &MultipleFoundError{"resource pool", path}
  678. }
  679. return rps[0], nil
  680. }
  681. func (f *Finder) DefaultResourcePool(ctx context.Context) (*object.ResourcePool, error) {
  682. rp, err := f.ResourcePool(ctx, "*/Resources")
  683. if err != nil {
  684. return nil, toDefaultError(err)
  685. }
  686. return rp, nil
  687. }
  688. func (f *Finder) ResourcePoolOrDefault(ctx context.Context, path string) (*object.ResourcePool, error) {
  689. if path != "" {
  690. rp, err := f.ResourcePool(ctx, path)
  691. if err != nil {
  692. return nil, err
  693. }
  694. return rp, nil
  695. }
  696. return f.DefaultResourcePool(ctx)
  697. }
  698. // ResourcePoolListAll combines ResourcePoolList and VirtualAppList
  699. // VirtualAppList is only called if ResourcePoolList does not find any pools with the given path.
  700. func (f *Finder) ResourcePoolListAll(ctx context.Context, path string) ([]*object.ResourcePool, error) {
  701. pools, err := f.ResourcePoolList(ctx, path)
  702. if err != nil {
  703. if _, ok := err.(*NotFoundError); !ok {
  704. return nil, err
  705. }
  706. vapps, _ := f.VirtualAppList(ctx, path)
  707. if len(vapps) == 0 {
  708. return nil, err
  709. }
  710. for _, vapp := range vapps {
  711. pools = append(pools, vapp.ResourcePool)
  712. }
  713. }
  714. return pools, nil
  715. }
  716. func (f *Finder) DefaultFolder(ctx context.Context) (*object.Folder, error) {
  717. ref, err := f.vmFolder(ctx)
  718. if err != nil {
  719. return nil, toDefaultError(err)
  720. }
  721. folder := object.NewFolder(f.client, ref.Reference())
  722. // Set the InventoryPath of the newly created folder object
  723. // The default foler becomes the datacenter's "vm" folder.
  724. // The "vm" folder always exists for a datacenter. It cannot be
  725. // removed or replaced
  726. folder.SetInventoryPath(path.Join(f.dc.InventoryPath, "vm"))
  727. return folder, nil
  728. }
  729. func (f *Finder) FolderOrDefault(ctx context.Context, path string) (*object.Folder, error) {
  730. if path != "" {
  731. folder, err := f.Folder(ctx, path)
  732. if err != nil {
  733. return nil, err
  734. }
  735. return folder, nil
  736. }
  737. return f.DefaultFolder(ctx)
  738. }
  739. func (f *Finder) VirtualMachineList(ctx context.Context, path string) ([]*object.VirtualMachine, error) {
  740. s := &spec{
  741. Relative: f.vmFolder,
  742. Parents: []string{"VirtualApp"},
  743. }
  744. es, err := f.find(ctx, path, s)
  745. if err != nil {
  746. return nil, err
  747. }
  748. var vms []*object.VirtualMachine
  749. for _, e := range es {
  750. switch o := e.Object.(type) {
  751. case mo.VirtualMachine:
  752. vm := object.NewVirtualMachine(f.client, o.Reference())
  753. vm.InventoryPath = e.Path
  754. vms = append(vms, vm)
  755. }
  756. }
  757. if len(vms) == 0 {
  758. return nil, &NotFoundError{"vm", path}
  759. }
  760. return vms, nil
  761. }
  762. func (f *Finder) VirtualMachine(ctx context.Context, path string) (*object.VirtualMachine, error) {
  763. vms, err := f.VirtualMachineList(ctx, path)
  764. if err != nil {
  765. return nil, err
  766. }
  767. if len(vms) > 1 {
  768. return nil, &MultipleFoundError{"vm", path}
  769. }
  770. return vms[0], nil
  771. }
  772. func (f *Finder) VirtualAppList(ctx context.Context, path string) ([]*object.VirtualApp, error) {
  773. s := &spec{
  774. Relative: f.vmFolder,
  775. }
  776. es, err := f.find(ctx, path, s)
  777. if err != nil {
  778. return nil, err
  779. }
  780. var apps []*object.VirtualApp
  781. for _, e := range es {
  782. switch o := e.Object.(type) {
  783. case mo.VirtualApp:
  784. app := object.NewVirtualApp(f.client, o.Reference())
  785. app.InventoryPath = e.Path
  786. apps = append(apps, app)
  787. }
  788. }
  789. if len(apps) == 0 {
  790. return nil, &NotFoundError{"app", path}
  791. }
  792. return apps, nil
  793. }
  794. func (f *Finder) VirtualApp(ctx context.Context, path string) (*object.VirtualApp, error) {
  795. apps, err := f.VirtualAppList(ctx, path)
  796. if err != nil {
  797. return nil, err
  798. }
  799. if len(apps) > 1 {
  800. return nil, &MultipleFoundError{"app", path}
  801. }
  802. return apps[0], nil
  803. }
  804. func (f *Finder) FolderList(ctx context.Context, path string) ([]*object.Folder, error) {
  805. es, err := f.ManagedObjectList(ctx, path)
  806. if err != nil {
  807. return nil, err
  808. }
  809. var folders []*object.Folder
  810. for _, e := range es {
  811. switch o := e.Object.(type) {
  812. case mo.Folder, mo.StoragePod:
  813. folder := object.NewFolder(f.client, o.Reference())
  814. folder.InventoryPath = e.Path
  815. folders = append(folders, folder)
  816. case *object.Folder:
  817. // RootFolder
  818. folders = append(folders, o)
  819. }
  820. }
  821. if len(folders) == 0 {
  822. return nil, &NotFoundError{"folder", path}
  823. }
  824. return folders, nil
  825. }
  826. func (f *Finder) Folder(ctx context.Context, path string) (*object.Folder, error) {
  827. folders, err := f.FolderList(ctx, path)
  828. if err != nil {
  829. return nil, err
  830. }
  831. if len(folders) > 1 {
  832. return nil, &MultipleFoundError{"folder", path}
  833. }
  834. return folders[0], nil
  835. }