github.com/vmware/govmomi@v0.51.0/view/task_view.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
     6  
     7  import (
     8  	"context"
     9  
    10  	"github.com/vmware/govmomi/property"
    11  	"github.com/vmware/govmomi/vim25/types"
    12  )
    13  
    14  // TaskView extends ListView such that it can follow a ManagedEntity's recentTask updates.
    15  type TaskView struct {
    16  	*ListView
    17  
    18  	Follow bool
    19  
    20  	Watch *types.ManagedObjectReference
    21  }
    22  
    23  // CreateTaskView creates a new ListView that optionally watches for a ManagedEntity's recentTask updates.
    24  func (m Manager) CreateTaskView(ctx context.Context, watch *types.ManagedObjectReference) (*TaskView, error) {
    25  	l, err := m.CreateListView(ctx, nil)
    26  	if err != nil {
    27  		return nil, err
    28  	}
    29  
    30  	tv := &TaskView{
    31  		ListView: l,
    32  		Watch:    watch,
    33  	}
    34  
    35  	return tv, nil
    36  }
    37  
    38  // Collect calls function f for each Task update.
    39  func (v TaskView) Collect(ctx context.Context, f func([]types.TaskInfo)) error {
    40  	// Using TaskHistoryCollector would be less clunky, but it isn't supported on ESX at all.
    41  	ref := v.Reference()
    42  	filter := new(property.WaitFilter).Add(ref, "Task", []string{"info"}, v.TraversalSpec())
    43  
    44  	if v.Watch != nil {
    45  		filter.Add(*v.Watch, v.Watch.Type, []string{"recentTask"})
    46  	}
    47  
    48  	pc := property.DefaultCollector(v.Client())
    49  
    50  	completed := make(map[string]bool)
    51  
    52  	return property.WaitForUpdates(ctx, pc, filter, func(updates []types.ObjectUpdate) bool {
    53  		var infos []types.TaskInfo
    54  		var prune []types.ManagedObjectReference
    55  		var tasks []types.ManagedObjectReference
    56  		var reset func()
    57  
    58  		for _, update := range updates {
    59  			for _, change := range update.ChangeSet {
    60  				if change.Name == "recentTask" {
    61  					tasks = change.Val.(types.ArrayOfManagedObjectReference).ManagedObjectReference
    62  					if len(tasks) != 0 {
    63  						reset = func() {
    64  							_, _ = v.Reset(ctx, tasks)
    65  
    66  							// Remember any tasks we've reported as complete already,
    67  							// to avoid reporting multiple times when Reset is triggered.
    68  							rtasks := make(map[string]bool)
    69  							for i := range tasks {
    70  								if _, ok := completed[tasks[i].Value]; ok {
    71  									rtasks[tasks[i].Value] = true
    72  								}
    73  							}
    74  							completed = rtasks
    75  						}
    76  					}
    77  
    78  					continue
    79  				}
    80  
    81  				info, ok := change.Val.(types.TaskInfo)
    82  				if !ok {
    83  					continue
    84  				}
    85  
    86  				if !completed[info.Task.Value] {
    87  					infos = append(infos, info)
    88  				}
    89  
    90  				if v.Follow && info.CompleteTime != nil {
    91  					prune = append(prune, info.Task)
    92  					completed[info.Task.Value] = true
    93  				}
    94  			}
    95  		}
    96  
    97  		if len(infos) != 0 {
    98  			f(infos)
    99  		}
   100  
   101  		if reset != nil {
   102  			reset()
   103  		} else if len(prune) != 0 {
   104  			_, _ = v.Remove(ctx, prune)
   105  		}
   106  
   107  		if len(tasks) != 0 && len(infos) == 0 {
   108  			return false
   109  		}
   110  
   111  		return !v.Follow
   112  	})
   113  }