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 }