github.com/vmware/govmomi@v0.51.0/cli/vm/power.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 vm
     6  
     7  import (
     8  	"context"
     9  	"flag"
    10  	"fmt"
    11  
    12  	"github.com/vmware/govmomi/cli"
    13  	"github.com/vmware/govmomi/cli/flags"
    14  	"github.com/vmware/govmomi/fault"
    15  	"github.com/vmware/govmomi/object"
    16  	"github.com/vmware/govmomi/vim25/types"
    17  )
    18  
    19  type power struct {
    20  	*flags.ClientFlag
    21  	*flags.SearchFlag
    22  
    23  	On       bool
    24  	Off      bool
    25  	Reset    bool
    26  	Reboot   bool
    27  	Shutdown bool
    28  	Standby  bool
    29  	Suspend  bool
    30  	Force    bool
    31  	Multi    bool
    32  	Wait     bool
    33  }
    34  
    35  func init() {
    36  	cli.Register("vm.power", &power{})
    37  }
    38  
    39  func (cmd *power) Register(ctx context.Context, f *flag.FlagSet) {
    40  	cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
    41  	cmd.ClientFlag.Register(ctx, f)
    42  
    43  	cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines)
    44  	cmd.SearchFlag.Register(ctx, f)
    45  
    46  	f.BoolVar(&cmd.On, "on", false, "Power on")
    47  	f.BoolVar(&cmd.Off, "off", false, "Power off")
    48  	f.BoolVar(&cmd.Reset, "reset", false, "Power reset")
    49  	f.BoolVar(&cmd.Suspend, "suspend", false, "Power suspend")
    50  	f.BoolVar(&cmd.Reboot, "r", false, "Reboot guest")
    51  	f.BoolVar(&cmd.Shutdown, "s", false, "Shutdown guest")
    52  	f.BoolVar(&cmd.Standby, "standby", false, "Standby guest")
    53  	f.BoolVar(&cmd.Force, "force", false, "Force (ignore state error and hard shutdown/reboot if tools unavailable)")
    54  	f.BoolVar(&cmd.Multi, "M", false, "Use Datacenter.PowerOnMultiVM method instead of VirtualMachine.PowerOnVM")
    55  	f.BoolVar(&cmd.Wait, "wait", true, "Wait for the operation to complete")
    56  }
    57  
    58  func (cmd *power) Usage() string {
    59  	return "NAME..."
    60  }
    61  
    62  func (cmd *power) Description() string {
    63  	return `Invoke VM power operations.
    64  
    65  Examples:
    66    govc vm.power -on VM1 VM2 VM3
    67    govc vm.power -on -M VM1 VM2 VM3
    68    govc vm.power -off -force VM1`
    69  }
    70  
    71  func (cmd *power) Process(ctx context.Context) error {
    72  	if err := cmd.ClientFlag.Process(ctx); err != nil {
    73  		return err
    74  	}
    75  	if err := cmd.SearchFlag.Process(ctx); err != nil {
    76  		return err
    77  	}
    78  	opts := []bool{cmd.On, cmd.Off, cmd.Reset, cmd.Suspend, cmd.Reboot, cmd.Shutdown, cmd.Standby}
    79  	selected := false
    80  
    81  	for _, opt := range opts {
    82  		if opt {
    83  			if selected {
    84  				return flag.ErrHelp
    85  			}
    86  			selected = opt
    87  		}
    88  	}
    89  
    90  	if !selected {
    91  		return flag.ErrHelp
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  func isToolsUnavailable(err error) bool {
    98  	return fault.Is(err, &types.ToolsUnavailable{})
    99  }
   100  
   101  // this is annoying, but the likely use cases for Datacenter.PowerOnVM outside of this command would
   102  // use []types.ManagedObjectReference via ContainerView or field such as ResourcePool.Vm rather than the Finder.
   103  func vmReferences(vms []*object.VirtualMachine) []types.ManagedObjectReference {
   104  	refs := make([]types.ManagedObjectReference, len(vms))
   105  	for i, vm := range vms {
   106  		refs[i] = vm.Reference()
   107  	}
   108  	return refs
   109  }
   110  
   111  func (cmd *power) Run(ctx context.Context, f *flag.FlagSet) error {
   112  	vms, err := cmd.VirtualMachines(f.Args())
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	if cmd.On && cmd.Multi {
   118  		dc, derr := cmd.Datacenter()
   119  		if derr != nil {
   120  			return derr
   121  		}
   122  
   123  		task, derr := dc.PowerOnVM(ctx, vmReferences(vms))
   124  		if derr != nil {
   125  			return derr
   126  		}
   127  
   128  		msg := fmt.Sprintf("Powering on %d VMs...", len(vms))
   129  		if task == nil {
   130  			// running against ESX
   131  			fmt.Fprintf(cmd, "%s OK\n", msg)
   132  			return nil
   133  		}
   134  
   135  		if cmd.Wait {
   136  			logger := cmd.ProgressLogger(msg)
   137  			defer logger.Wait()
   138  
   139  			_, err = task.WaitForResult(ctx, logger)
   140  			return err
   141  		}
   142  	}
   143  
   144  	for _, vm := range vms {
   145  		var task *object.Task
   146  
   147  		switch {
   148  		case cmd.On:
   149  			fmt.Fprintf(cmd, "Powering on %s... ", vm.Reference())
   150  			task, err = vm.PowerOn(ctx)
   151  		case cmd.Off:
   152  			fmt.Fprintf(cmd, "Powering off %s... ", vm.Reference())
   153  			task, err = vm.PowerOff(ctx)
   154  		case cmd.Reset:
   155  			fmt.Fprintf(cmd, "Reset %s... ", vm.Reference())
   156  			task, err = vm.Reset(ctx)
   157  		case cmd.Suspend:
   158  			fmt.Fprintf(cmd, "Suspend %s... ", vm.Reference())
   159  			task, err = vm.Suspend(ctx)
   160  		case cmd.Reboot:
   161  			fmt.Fprintf(cmd, "Reboot guest %s... ", vm.Reference())
   162  			err = vm.RebootGuest(ctx)
   163  
   164  			if err != nil && cmd.Force && isToolsUnavailable(err) {
   165  				task, err = vm.Reset(ctx)
   166  			}
   167  		case cmd.Shutdown:
   168  			fmt.Fprintf(cmd, "Shutdown guest %s... ", vm.Reference())
   169  			err = vm.ShutdownGuest(ctx)
   170  
   171  			if err != nil && cmd.Force && isToolsUnavailable(err) {
   172  				task, err = vm.PowerOff(ctx)
   173  			}
   174  		case cmd.Standby:
   175  			fmt.Fprintf(cmd, "Standby guest %s... ", vm.Reference())
   176  			err = vm.StandbyGuest(ctx)
   177  
   178  			if err != nil && cmd.Force && isToolsUnavailable(err) {
   179  				task, err = vm.Suspend(ctx)
   180  			}
   181  		}
   182  
   183  		if err != nil {
   184  			return err
   185  		}
   186  
   187  		if cmd.Wait && task != nil {
   188  			err = task.Wait(ctx)
   189  		}
   190  		if err == nil {
   191  			fmt.Fprintf(cmd, "OK\n")
   192  			continue
   193  		}
   194  
   195  		if cmd.Force {
   196  			fmt.Fprintf(cmd, "Error: %s\n", err)
   197  			continue
   198  		}
   199  
   200  		return err
   201  	}
   202  
   203  	return nil
   204  }