github.com/vmware/govmomi@v0.43.0/govc/vm/power.go (about)

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