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  }