code: func ShutdownGuest(client *govmomi.Client, vm *object.VirtualMachine, timeout int) error {
  	log.Printf("[DEBUG] Attempting guest shutdown of virtual machine %q", vm.InventoryPath)
  	sctx, scancel := context.WithTimeout(context.Background(), provider.DefaultAPITimeout)
  	defer scancel()
  	if err := vm.ShutdownGuest(sctx); err != nil {
  		return err
  	}
  
  	// We now wait on VM power state to be powerOff, via a property collector that waits on power state.
  	p := client.PropertyCollector()
  	if timeout < 1 {
  		timeout = 1
  	}
  	pctx, pcancel := context.WithTimeout(context.Background(), time.Minute*time.Duration(timeout))
  	defer pcancel()
  
  	err := property.Wait(pctx, p, vm.Reference(), []string{"runtime.powerState"}, func(pc []types.PropertyChange) bool {
  		for _, c := range pc {
  			if c.Op != types.PropertyChangeOpAssign {
  				continue
  			}
  
  			switch v := c.Val.(type) {
  			case types.VirtualMachinePowerState:
  				if v == types.VirtualMachinePowerStatePoweredOff {
  					return true
  				}
  			}
  		}
  
  		return false
  	})
  
  	if err != nil {
  		// Provide a friendly error message if we timed out waiting for a shutdown.
  		if pctx.Err() == context.DeadlineExceeded {
  			return errGuestShutdownTimeout
  		}
  		return err
  	}
  	return nil
  }
docs: // ShutdownGuest wraps the graceful shutdown of a guest VM, and then waiting an
  // appropriate amount of time for the guest power state to go to powered off.
  // If the VM does not power off in the shutdown period specified by timeout (in
  // minutes), an error is returned.
  //
  // The minimum value for timeout is 1 minute - setting to a 0 or negative value
  // is not allowed and will just reset the timeout to the minimum.