github.com/vmware/govmomi@v0.51.0/view/example_test.go (about)

     1  // © Broadcom. All Rights Reserved.
     2  // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package view_test
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"log"
    11  	"sort"
    12  	"sync"
    13  	"time"
    14  
    15  	"github.com/vmware/govmomi/find"
    16  	"github.com/vmware/govmomi/object"
    17  	"github.com/vmware/govmomi/property"
    18  	"github.com/vmware/govmomi/simulator"
    19  	"github.com/vmware/govmomi/view"
    20  	"github.com/vmware/govmomi/vim25"
    21  	"github.com/vmware/govmomi/vim25/methods"
    22  	"github.com/vmware/govmomi/vim25/mo"
    23  	"github.com/vmware/govmomi/vim25/types"
    24  )
    25  
    26  // Create a view of all hosts in the inventory, printing host names that belong to a cluster and excluding standalone hosts.
    27  func ExampleContainerView_Retrieve() {
    28  	model := simulator.VPX()
    29  	model.Datacenter = 2
    30  
    31  	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
    32  		m := view.NewManager(c)
    33  		kind := []string{"HostSystem"}
    34  
    35  		v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true)
    36  		if err != nil {
    37  			log.Fatal(err)
    38  		}
    39  
    40  		var hosts []mo.HostSystem
    41  		var names []string
    42  
    43  		err = v.Retrieve(ctx, kind, []string{"summary.config.name", "parent"}, &hosts)
    44  		if err != nil {
    45  			return err
    46  		}
    47  
    48  		for _, host := range hosts {
    49  			if host.Parent.Type != "ClusterComputeResource" {
    50  				continue
    51  			}
    52  			names = append(names, host.Summary.Config.Name)
    53  		}
    54  
    55  		sort.Strings(names)
    56  		fmt.Println(names)
    57  
    58  		return v.Destroy(ctx)
    59  	}, model)
    60  	// Output: [DC0_C0_H0 DC0_C0_H1 DC0_C0_H2 DC1_C0_H0 DC1_C0_H1 DC1_C0_H2]
    61  }
    62  
    63  func ExampleContainerView_retrieveClusters() {
    64  	model := simulator.VPX()
    65  	model.Cluster = 3
    66  
    67  	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
    68  		m := view.NewManager(c)
    69  		kind := []string{"ClusterComputeResource"}
    70  
    71  		v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true)
    72  		if err != nil {
    73  			log.Fatal(err)
    74  		}
    75  
    76  		var clusters []mo.ClusterComputeResource
    77  		var names []string
    78  
    79  		err = v.Retrieve(ctx, kind, []string{"name"}, &clusters)
    80  		if err != nil {
    81  			return err
    82  		}
    83  
    84  		for _, cluster := range clusters {
    85  			names = append(names, cluster.Name)
    86  		}
    87  
    88  		sort.Strings(names)
    89  		fmt.Println(names)
    90  
    91  		return v.Destroy(ctx)
    92  	}, model)
    93  	// Output: [DC0_C0 DC0_C1 DC0_C2]
    94  }
    95  
    96  // Create a view of all VMs in the inventory, printing VM names that end with "_VM1".
    97  func ExampleContainerView_RetrieveWithFilter() {
    98  	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
    99  		m := view.NewManager(c)
   100  		kind := []string{"VirtualMachine"}
   101  
   102  		v, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true)
   103  		if err != nil {
   104  			log.Fatal(err)
   105  		}
   106  
   107  		var vms []mo.VirtualMachine
   108  		var names []string
   109  
   110  		err = v.RetrieveWithFilter(ctx, kind, []string{"name"}, &vms, property.Match{"name": "*_VM1"})
   111  		if err != nil {
   112  			return err
   113  		}
   114  
   115  		for _, vm := range vms {
   116  			names = append(names, vm.Name)
   117  		}
   118  
   119  		sort.Strings(names)
   120  		fmt.Println(names)
   121  
   122  		return v.Destroy(ctx)
   123  	})
   124  	// Output: [DC0_C0_RP0_VM1 DC0_H0_VM1]
   125  }
   126  
   127  // Create a view of all VMs in a specific subfolder, powering off all VMs within
   128  func ExampleContainerView_Find() {
   129  	model := simulator.VPX()
   130  	model.Folder = 1 // put everything inside subfolders
   131  
   132  	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
   133  		folder, err := object.NewSearchIndex(c).FindByInventoryPath(ctx, "/F0/DC0/vm/F0")
   134  		if err != nil {
   135  			return err
   136  		}
   137  
   138  		m := view.NewManager(c)
   139  		kind := []string{"VirtualMachine"} // include VMs only, ignoring other object types
   140  
   141  		// Root of the view is the subfolder moid (true == recurse into any subfolders of the root)
   142  		v, err := m.CreateContainerView(ctx, folder.Reference(), kind, true)
   143  		if err != nil {
   144  			log.Fatal(err)
   145  		}
   146  
   147  		vms, err := v.Find(ctx, kind, property.Match{})
   148  		if err != nil {
   149  			return err
   150  		}
   151  
   152  		for _, id := range vms {
   153  			vm := object.NewVirtualMachine(c, id)
   154  			task, err := vm.PowerOff(ctx)
   155  			if err != nil {
   156  				return err
   157  			}
   158  
   159  			if err = task.Wait(ctx); err != nil {
   160  				return err
   161  			}
   162  		}
   163  
   164  		fmt.Println(len(vms))
   165  
   166  		return v.Destroy(ctx)
   167  	}, model)
   168  	// Output: 4
   169  }
   170  
   171  // This example uses a single PropertyCollector with ListView for waiting on updates to N tasks
   172  func ExampleListView_tasks() {
   173  	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
   174  		list, err := view.NewManager(c).CreateListView(ctx, nil)
   175  		if err != nil {
   176  			return err
   177  		}
   178  
   179  		defer list.Destroy(ctx)
   180  
   181  		vms, err := find.NewFinder(c).VirtualMachineList(ctx, "*")
   182  		if err != nil {
   183  			return err
   184  		}
   185  
   186  		result := map[types.TaskInfoState]int{}
   187  		n := len(vms)
   188  		p := property.DefaultCollector(c)
   189  
   190  		// wait for any updates to tasks in our list view
   191  		filter := new(property.WaitFilter).Add(list.Reference(), "Task", []string{"info"}, list.TraversalSpec())
   192  
   193  		var werr error
   194  		var wg sync.WaitGroup
   195  		wg.Add(1)
   196  		go func() { // WaitForUpdates blocks until func returns true
   197  			defer wg.Done()
   198  			werr = property.WaitForUpdates(ctx, p, filter, func(updates []types.ObjectUpdate) bool {
   199  				for _, update := range updates {
   200  					for _, change := range update.ChangeSet {
   201  						info := change.Val.(types.TaskInfo)
   202  
   203  						switch info.State {
   204  						case types.TaskInfoStateSuccess, types.TaskInfoStateError:
   205  							_, _ = list.Remove(ctx, []types.ManagedObjectReference{update.Obj})
   206  							result[info.State]++
   207  							n--
   208  							if n == 0 {
   209  								return true
   210  							}
   211  						}
   212  					}
   213  				}
   214  
   215  				return false
   216  			})
   217  		}()
   218  
   219  		for _, vm := range vms {
   220  			task, err := vm.PowerOff(ctx)
   221  			if err != nil {
   222  				return err
   223  			}
   224  			_, err = list.Add(ctx, []types.ManagedObjectReference{task.Reference()})
   225  			if err != nil {
   226  				return err
   227  			}
   228  		}
   229  
   230  		wg.Wait() // wait until all tasks complete and WaitForUpdates returns
   231  
   232  		for state, n := range result {
   233  			fmt.Printf("%s=%d", state, n)
   234  		}
   235  
   236  		return werr
   237  	})
   238  	// Output: success=4
   239  }
   240  
   241  // viewOfVM returns a spec to traverse a ListView of ContainerView, for tracking VM updates.
   242  func viewOfVM(ref types.ManagedObjectReference, pathSet []string) types.CreateFilter {
   243  	return types.CreateFilter{
   244  		Spec: types.PropertyFilterSpec{
   245  			ObjectSet: []types.ObjectSpec{{
   246  				Obj:  ref,
   247  				Skip: types.NewBool(true),
   248  				SelectSet: []types.BaseSelectionSpec{
   249  					// ListView --> ContainerView
   250  					&types.TraversalSpec{
   251  						Type: "ListView",
   252  						Path: "view",
   253  						SelectSet: []types.BaseSelectionSpec{
   254  							&types.SelectionSpec{
   255  								Name: "visitViews",
   256  							},
   257  						},
   258  					},
   259  					// ContainerView --> VM
   260  					&types.TraversalSpec{
   261  						SelectionSpec: types.SelectionSpec{
   262  							Name: "visitViews",
   263  						},
   264  						Type: "ContainerView",
   265  						Path: "view",
   266  					},
   267  				},
   268  			}},
   269  			PropSet: []types.PropertySpec{{
   270  				Type:    "VirtualMachine",
   271  				PathSet: pathSet,
   272  			}},
   273  		},
   274  	}
   275  }
   276  
   277  // Example of using WaitForUpdates with a ListView of ContainerView.
   278  // Each container root is a Cluster view of VirtualMachines.
   279  // Modifying the ListView changes which VirtualMachine updates are returned by WaitForUpdates.
   280  func ExampleListView_ofContainerView() {
   281  	model := simulator.VPX()
   282  	model.Cluster = 3
   283  
   284  	simulator.Run(func(ctx context.Context, c *vim25.Client) error {
   285  		m := view.NewManager(c)
   286  
   287  		kind := []string{"ClusterComputeResource"}
   288  		root, err := m.CreateContainerView(ctx, c.ServiceContent.RootFolder, kind, true)
   289  		if err != nil {
   290  			return err
   291  		}
   292  
   293  		clusters, err := root.Find(ctx, kind, property.Match{})
   294  		if err != nil {
   295  			return err
   296  		}
   297  
   298  		list, err := m.CreateListView(ctx, nil)
   299  		if err != nil {
   300  			return err
   301  		}
   302  
   303  		kind = []string{"VirtualMachine"}
   304  		views := make(map[types.ManagedObjectReference]*view.ContainerView)
   305  
   306  		for _, cluster := range clusters {
   307  			cv, err := m.CreateContainerView(ctx, cluster, kind, true)
   308  			if err != nil {
   309  				return err
   310  			}
   311  
   312  			_, err = list.Add(ctx, []types.ManagedObjectReference{cv.Reference()})
   313  
   314  			views[cluster] = cv
   315  		}
   316  
   317  		pc := property.DefaultCollector(c)
   318  
   319  		pathSet := []string{"config.extraConfig"}
   320  		pf, err := pc.CreateFilter(ctx, viewOfVM(list.Reference(), pathSet))
   321  		if err != nil {
   322  			return err
   323  		}
   324  		defer pf.Destroy(ctx)
   325  
   326  		// MaxWaitSeconds value of 0 causes WaitForUpdatesEx to do one update calculation and return any results.
   327  		req := types.WaitForUpdatesEx{
   328  			This: pc.Reference(),
   329  			Options: &types.WaitOptions{
   330  				MaxWaitSeconds: types.NewInt32(0),
   331  			},
   332  		}
   333  
   334  		updates := func() ([]types.ObjectUpdate, error) {
   335  			res, err := methods.WaitForUpdatesEx(ctx, c.Client, &req)
   336  			if err != nil {
   337  				return nil, err
   338  			}
   339  
   340  			set := res.Returnval
   341  
   342  			if set == nil {
   343  				return nil, nil
   344  			}
   345  
   346  			req.Version = set.Version
   347  
   348  			if len(set.FilterSet) == 0 {
   349  				return nil, nil
   350  			}
   351  
   352  			return set.FilterSet[0].ObjectSet, nil
   353  		}
   354  
   355  		set, err := updates()
   356  		if err != nil {
   357  			return err
   358  		}
   359  
   360  		all := make([]types.ManagedObjectReference, len(set))
   361  		for i := range set {
   362  			all[i] = set[i].Obj
   363  		}
   364  
   365  		fmt.Printf("Initial updates=%d\n", len(all))
   366  
   367  		reconfig := func() {
   368  			spec := types.VirtualMachineConfigSpec{
   369  				ExtraConfig: []types.BaseOptionValue{
   370  					&types.OptionValue{Key: "time", Value: time.Now().String()},
   371  				},
   372  			}
   373  			// Change state of all VMs in all Clusters
   374  			for _, ref := range all {
   375  				task, err := object.NewVirtualMachine(c, ref).Reconfigure(ctx, spec)
   376  				if err != nil {
   377  					panic(err)
   378  				}
   379  				if err = task.Wait(ctx); err != nil {
   380  					panic(err)
   381  				}
   382  			}
   383  
   384  			set, err := updates()
   385  			if err != nil {
   386  				panic(err)
   387  			}
   388  
   389  			fmt.Printf("Reconfig updates=%d\n", len(set))
   390  		}
   391  
   392  		reconfig()
   393  
   394  		cluster := views[clusters[0]].Reference()
   395  		_, err = list.Remove(ctx, []types.ManagedObjectReference{cluster})
   396  		if err != nil {
   397  			return err
   398  		}
   399  
   400  		reconfig()
   401  
   402  		_, err = list.Add(ctx, []types.ManagedObjectReference{cluster})
   403  		if err != nil {
   404  			return err
   405  		}
   406  
   407  		reconfig()
   408  
   409  		return nil
   410  	}, model)
   411  
   412  	// Output:
   413  	// Initial updates=6
   414  	// Reconfig updates=6
   415  	// Reconfig updates=4
   416  	// Reconfig updates=6
   417  }