github.com/vmware/govmomi@v0.43.0/view/task_view.go (about) 1 /* 2 Copyright (c) 2017 VMware, Inc. All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package view 18 19 import ( 20 "context" 21 22 "github.com/vmware/govmomi/property" 23 "github.com/vmware/govmomi/vim25/types" 24 ) 25 26 // TaskView extends ListView such that it can follow a ManagedEntity's recentTask updates. 27 type TaskView struct { 28 *ListView 29 30 Follow bool 31 32 Watch *types.ManagedObjectReference 33 } 34 35 // CreateTaskView creates a new ListView that optionally watches for a ManagedEntity's recentTask updates. 36 func (m Manager) CreateTaskView(ctx context.Context, watch *types.ManagedObjectReference) (*TaskView, error) { 37 l, err := m.CreateListView(ctx, nil) 38 if err != nil { 39 return nil, err 40 } 41 42 tv := &TaskView{ 43 ListView: l, 44 Watch: watch, 45 } 46 47 return tv, nil 48 } 49 50 // Collect calls function f for each Task update. 51 func (v TaskView) Collect(ctx context.Context, f func([]types.TaskInfo)) error { 52 // Using TaskHistoryCollector would be less clunky, but it isn't supported on ESX at all. 53 ref := v.Reference() 54 filter := new(property.WaitFilter).Add(ref, "Task", []string{"info"}, v.TraversalSpec()) 55 56 if v.Watch != nil { 57 filter.Add(*v.Watch, v.Watch.Type, []string{"recentTask"}) 58 } 59 60 pc := property.DefaultCollector(v.Client()) 61 62 completed := make(map[string]bool) 63 64 return property.WaitForUpdates(ctx, pc, filter, func(updates []types.ObjectUpdate) bool { 65 var infos []types.TaskInfo 66 var prune []types.ManagedObjectReference 67 var tasks []types.ManagedObjectReference 68 var reset func() 69 70 for _, update := range updates { 71 for _, change := range update.ChangeSet { 72 if change.Name == "recentTask" { 73 tasks = change.Val.(types.ArrayOfManagedObjectReference).ManagedObjectReference 74 if len(tasks) != 0 { 75 reset = func() { 76 _, _ = v.Reset(ctx, tasks) 77 78 // Remember any tasks we've reported as complete already, 79 // to avoid reporting multiple times when Reset is triggered. 80 rtasks := make(map[string]bool) 81 for i := range tasks { 82 if _, ok := completed[tasks[i].Value]; ok { 83 rtasks[tasks[i].Value] = true 84 } 85 } 86 completed = rtasks 87 } 88 } 89 90 continue 91 } 92 93 info, ok := change.Val.(types.TaskInfo) 94 if !ok { 95 continue 96 } 97 98 if !completed[info.Task.Value] { 99 infos = append(infos, info) 100 } 101 102 if v.Follow && info.CompleteTime != nil { 103 prune = append(prune, info.Task) 104 completed[info.Task.Value] = true 105 } 106 } 107 } 108 109 if len(infos) != 0 { 110 f(infos) 111 } 112 113 if reset != nil { 114 reset() 115 } else if len(prune) != 0 { 116 _, _ = v.Remove(ctx, prune) 117 } 118 119 if len(tasks) != 0 && len(infos) == 0 { 120 return false 121 } 122 123 return !v.Follow 124 }) 125 }