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  }