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