github.com/vmware/govmomi@v0.51.0/cli/flags/cluster.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 flags 6 7 import ( 8 "context" 9 "flag" 10 "fmt" 11 "os" 12 13 "github.com/vmware/govmomi/object" 14 "github.com/vmware/govmomi/property" 15 "github.com/vmware/govmomi/view" 16 "github.com/vmware/govmomi/vim25/mo" 17 "github.com/vmware/govmomi/vim25/types" 18 ) 19 20 type ClusterFlag struct { 21 common 22 23 *DatacenterFlag 24 25 Name string 26 27 cluster *object.ClusterComputeResource 28 pc *property.Collector 29 } 30 31 var clusterFlagKey = flagKey("cluster") 32 33 func NewClusterFlag(ctx context.Context) (*ClusterFlag, context.Context) { 34 if v := ctx.Value(clusterFlagKey); v != nil { 35 return v.(*ClusterFlag), ctx 36 } 37 38 v := &ClusterFlag{} 39 v.DatacenterFlag, ctx = NewDatacenterFlag(ctx) 40 ctx = context.WithValue(ctx, clusterFlagKey, v) 41 return v, ctx 42 } 43 44 func (f *ClusterFlag) Register(ctx context.Context, fs *flag.FlagSet) { 45 f.RegisterOnce(func() { 46 f.DatacenterFlag.Register(ctx, fs) 47 48 env := "GOVC_CLUSTER" 49 value := os.Getenv(env) 50 usage := fmt.Sprintf("Cluster [%s]", env) 51 fs.StringVar(&f.Name, "cluster", value, usage) 52 }) 53 } 54 55 // RegisterPlacement registers the -cluster flag without using GOVC_CLUSTER env as the default value, 56 // usage is specific to VM placement. 57 func (f *ClusterFlag) RegisterPlacement(ctx context.Context, fs *flag.FlagSet) { 58 f.RegisterOnce(func() { 59 f.DatacenterFlag.Register(ctx, fs) 60 61 fs.StringVar(&f.Name, "cluster", "", "Use cluster for VM placement via DRS") 62 }) 63 } 64 65 func (f *ClusterFlag) Process(ctx context.Context) error { 66 return f.ProcessOnce(func() error { 67 if err := f.DatacenterFlag.Process(ctx); err != nil { 68 return err 69 } 70 return nil 71 }) 72 } 73 74 func (f *ClusterFlag) Cluster() (*object.ClusterComputeResource, error) { 75 if f.cluster != nil { 76 return f.cluster, nil 77 } 78 79 finder, err := f.Finder() 80 if err != nil { 81 return nil, err 82 } 83 84 if f.cluster, err = finder.ClusterComputeResourceOrDefault(context.TODO(), f.Name); err != nil { 85 return nil, err 86 } 87 88 f.pc = property.DefaultCollector(f.cluster.Client()) 89 90 return f.cluster, nil 91 } 92 93 func (f *ClusterFlag) ClusterIfSpecified() (*object.ClusterComputeResource, error) { 94 if f.Name == "" { 95 return nil, nil 96 } 97 return f.Cluster() 98 } 99 100 func (f *ClusterFlag) Reconfigure(ctx context.Context, spec types.BaseComputeResourceConfigSpec) error { 101 cluster, err := f.Cluster() 102 if err != nil { 103 return err 104 } 105 106 task, err := cluster.Reconfigure(ctx, spec, true) 107 if err != nil { 108 return err 109 } 110 111 logger := f.ProgressLogger(fmt.Sprintf("Reconfigure %s...", cluster.InventoryPath)) 112 defer logger.Wait() 113 114 _, err = task.WaitForResult(ctx, logger) 115 return err 116 } 117 118 func (f *ClusterFlag) objectMap(ctx context.Context, kind string, names []string) (map[string]types.ManagedObjectReference, error) { 119 cluster, err := f.Cluster() 120 if err != nil { 121 return nil, err 122 } 123 124 objects := make(map[string]types.ManagedObjectReference, len(names)) 125 for _, name := range names { 126 objects[name] = types.ManagedObjectReference{} 127 } 128 129 m := view.NewManager(cluster.Client()) 130 v, err := m.CreateContainerView(ctx, cluster.Reference(), []string{kind}, true) 131 if err != nil { 132 return nil, err 133 } 134 135 defer func() { 136 _ = v.Destroy(ctx) 137 }() 138 139 var entities []mo.ManagedEntity 140 141 err = v.Retrieve(ctx, []string{"ManagedEntity"}, []string{"name"}, &entities) 142 if err != nil { 143 return nil, err 144 } 145 146 for _, e := range entities { 147 if _, ok := objects[e.Name]; ok { 148 objects[e.Name] = e.Self 149 } 150 } 151 152 for name, ref := range objects { 153 if ref.Value == "" { 154 return nil, fmt.Errorf("%s %q not found", kind, name) 155 } 156 } 157 158 return objects, nil 159 } 160 161 func (f *ClusterFlag) ObjectList(ctx context.Context, kind string, names []string) ([]types.ManagedObjectReference, error) { 162 objs, err := f.objectMap(ctx, kind, names) 163 if err != nil { 164 return nil, err 165 } 166 167 var refs []types.ManagedObjectReference 168 169 for _, name := range names { // preserve order 170 refs = append(refs, objs[name]) 171 } 172 173 return refs, nil 174 } 175 176 func (f *ClusterFlag) Names(ctx context.Context, refs []types.ManagedObjectReference) (map[types.ManagedObjectReference]string, error) { 177 names := make(map[types.ManagedObjectReference]string, len(refs)) 178 179 if len(refs) != 0 { 180 var objs []mo.ManagedEntity 181 err := f.pc.Retrieve(ctx, refs, []string{"name"}, &objs) 182 if err != nil { 183 return nil, err 184 } 185 186 for _, obj := range objs { 187 names[obj.Self] = obj.Name 188 } 189 } 190 191 return names, nil 192 }