1/* 2Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package vm 18 19import ( 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 31type 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 Suspend bool 41 Force bool 42 Multi bool 43} 44 45func init() { 46 cli.Register("vm.power", &power{}) 47} 48 49func (cmd *power) Register(ctx context.Context, f *flag.FlagSet) { 50 cmd.ClientFlag, ctx = flags.NewClientFlag(ctx) 51 cmd.ClientFlag.Register(ctx, f) 52 53 cmd.SearchFlag, ctx = flags.NewSearchFlag(ctx, flags.SearchVirtualMachines) 54 cmd.SearchFlag.Register(ctx, f) 55 56 f.BoolVar(&cmd.On, "on", false, "Power on") 57 f.BoolVar(&cmd.Off, "off", false, "Power off") 58 f.BoolVar(&cmd.Reset, "reset", false, "Power reset") 59 f.BoolVar(&cmd.Suspend, "suspend", false, "Power suspend") 60 f.BoolVar(&cmd.Reboot, "r", false, "Reboot guest") 61 f.BoolVar(&cmd.Shutdown, "s", false, "Shutdown guest") 62 f.BoolVar(&cmd.Force, "force", false, "Force (ignore state error and hard shutdown/reboot if tools unavailable)") 63 f.BoolVar(&cmd.Multi, "M", false, "Use Datacenter.PowerOnMultiVM method instead of VirtualMachine.PowerOnVM") 64} 65 66func (cmd *power) Process(ctx context.Context) error { 67 if err := cmd.ClientFlag.Process(ctx); err != nil { 68 return err 69 } 70 if err := cmd.SearchFlag.Process(ctx); err != nil { 71 return err 72 } 73 opts := []bool{cmd.On, cmd.Off, cmd.Reset, cmd.Suspend, cmd.Reboot, cmd.Shutdown} 74 selected := false 75 76 for _, opt := range opts { 77 if opt { 78 if selected { 79 return flag.ErrHelp 80 } 81 selected = opt 82 } 83 } 84 85 if !selected { 86 return flag.ErrHelp 87 } 88 89 return nil 90} 91 92func isToolsUnavailable(err error) bool { 93 if soap.IsSoapFault(err) { 94 soapFault := soap.ToSoapFault(err) 95 if _, ok := soapFault.VimFault().(types.ToolsUnavailable); ok { 96 return ok 97 } 98 } 99 100 return false 101} 102 103// this is annoying, but the likely use cases for Datacenter.PowerOnVM outside of this command would 104// use []types.ManagedObjectReference via ContainerView or field such as ResourcePool.Vm rather than the Finder. 105func vmReferences(vms []*object.VirtualMachine) []types.ManagedObjectReference { 106 refs := make([]types.ManagedObjectReference, len(vms)) 107 for i, vm := range vms { 108 refs[i] = vm.Reference() 109 } 110 return refs 111} 112 113func (cmd *power) Run(ctx context.Context, f *flag.FlagSet) error { 114 vms, err := cmd.VirtualMachines(f.Args()) 115 if err != nil { 116 return err 117 } 118 119 if cmd.On && cmd.Multi { 120 dc, derr := cmd.Datacenter() 121 if derr != nil { 122 return derr 123 } 124 125 task, derr := dc.PowerOnVM(ctx, vmReferences(vms)) 126 if derr != nil { 127 return derr 128 } 129 130 msg := fmt.Sprintf("Powering on %d VMs...", len(vms)) 131 if task == nil { 132 // running against ESX 133 fmt.Fprintf(cmd, "%s OK\n", msg) 134 return nil 135 } 136 137 logger := cmd.ProgressLogger(msg) 138 defer logger.Wait() 139 140 _, err = task.WaitForResult(ctx, logger) 141 return err 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 } 175 176 if err != nil { 177 return err 178 } 179 180 if task != nil { 181 err = task.Wait(ctx) 182 } 183 if err == nil { 184 fmt.Fprintf(cmd, "OK\n") 185 continue 186 } 187 188 if cmd.Force { 189 fmt.Fprintf(cmd, "Error: %s\n", err) 190 continue 191 } 192 193 return err 194 } 195 196 return nil 197} 198