/*************************************************************************** * Copyright (c) 2013 VMware, Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ /*************************************************************************** * Copyright (c) 2012 VMware, Inc. All Rights Reserved. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ***************************************************************************/ package com.vmware.vhadoop.vhm.edpolicy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; import com.vmware.vhadoop.external.VCActionDTOTypes.HostDTO; import com.vmware.vhadoop.external.VCActionDTOTypes.VMDTO; import com.vmware.vhadoop.external.VCActionDTOTypes.VMPowerState; import com.vmware.vhadoop.external.VCActions; import com.vmware.vhadoop.util.CompoundStatus; import com.vmware.vhadoop.util.ProgressLogger; import com.vmware.vhadoop.vhm.TTStatesForHost; public abstract class AbstractEDP implements EnableDisableTTPolicy { private VCActions _vc; private static final String _className = AbstractEDP.class.getName(); static final ProgressLogger _pLog = ProgressLogger.getProgressLogger(_className); static final Logger _log = _pLog.getLogger(); private static final int shutdownGuestTimeOutMs = 30000; public AbstractEDP(VCActions vc) { _vc = vc; } private class FuturePowerStateAndVM { Future<VMPowerState> _powerState; VMDTO _vm; } private class EnabledDisabledVMLists { HostDTO _host; List<VMDTO> _enabledVMs = new ArrayList<VMDTO>(); List<VMDTO> _disabledVMs = new ArrayList<VMDTO>(); public EnabledDisabledVMLists(HostDTO host) { _host = host; } } @Override public TTStatesForHost[] getStateForTTs(VMDTO[] ttVMs) throws Exception { Map<String, EnabledDisabledVMLists> results = new HashMap<String, EnabledDisabledVMLists>(); /* TODO: Currently our VC calls to get host and power state are synchronously * getting cached data, so the parallelism isn't necessary - it could be in future */ /* Power state calls to VC are done in parallel for speed */ List<FuturePowerStateAndVM> powerStateTasks = new ArrayList<FuturePowerStateAndVM>(); for (VMDTO vm : ttVMs) { FuturePowerStateAndVM fpsav = new FuturePowerStateAndVM(); fpsav._powerState = _vc.getPowerState(vm, false); fpsav._vm = vm; powerStateTasks.add(fpsav); /* Build a map of hosts ready for the results below */ HostDTO host = _vc.getHostForVM(vm, false).get(); if (!results.containsKey(host._name)) { /* Assumption: host name is the unique key */ results.put(host._name, new EnabledDisabledVMLists(host)); } } /* Then we go back, get the results and divide up the VMs */ for (FuturePowerStateAndVM state : powerStateTasks) { HostDTO host = _vc.getHostForVM(state._vm, false).get(); VMDTO ttVM = state._vm; switch (state._powerState.get()) { case POWERED_ON: results.get(host._name)._enabledVMs.add(ttVM); break; case POWERED_OFF: results.get(host._name)._disabledVMs.add(ttVM); break; } } /* Convert the ordered lists and maps into something consumable */ TTStatesForHost[] returnVal = new TTStatesForHost[results.size()]; int cntr = 0; for (String hostName : results.keySet()) { EnabledDisabledVMLists lists = results.get(hostName); TTStatesForHost ttStates = new TTStatesForHost(lists._host, lists._enabledVMs, lists._disabledVMs); returnVal[cntr++] = ttStates; } return returnVal; } /* Return value indicates that all succeeded */ CompoundStatus blockOnVMTaskCompletion(List<Future<VMDTO>> vmTasks) { CompoundStatus status = new CompoundStatus("blockOnVMTaskCompletion"); for (Future<? extends Object> result : vmTasks) { try { if (result.get() == null) { status.registerTaskFailed(false, "null was unexpectedly returned from a future task"); } else { status.registerTaskSucceeded(); } } catch (Exception e) { throw new RuntimeException(e); } } return status; } CompoundStatus powerOnVMs(VMDTO[] toPowerOn) { CompoundStatus status = new CompoundStatus("powerOnVMs"); List<Future<VMDTO>> powerOnTasks = new ArrayList<Future<VMDTO>>(); for (VMDTO vm : toPowerOn) { _log.log(Level.INFO, "Enabling VM "+vm._name+" ..."); try { VMPowerState vmp = getVC().getPowerState(vm, false).get(); if (!vmp.equals(VMPowerState.POWERED_ON)) { powerOnTasks.add(getVC().powerOnVM(vm)); } } catch (Exception e) { String errorMsg = "Problem determining current power state of vm "+vm._name; _log.log(Level.SEVERE, errorMsg); status.registerTaskFailed(false, errorMsg); } } _log.log(Level.INFO, "Waiting for completion..."); if (powerOnTasks.size() > 0) { status.addStatus(blockOnVMTaskCompletion(powerOnTasks)); /* Currently blocking */ status.addStatus(testForPowerState(toPowerOn, true/*->powered-on*/)); } else { status.registerTaskSucceeded(); } _log.log(Level.INFO, "Done"); return status; } CompoundStatus powerOffVMs(VMDTO[] toPowerOff) { CompoundStatus status = new CompoundStatus("powerOffVMs"); List<Future<VMDTO>> powerOffTasks = new ArrayList<Future<VMDTO>>(); for (VMDTO vm : toPowerOff) { _log.log(Level.INFO, "Disabling VM "+vm._name+" ..."); powerOffTasks.add(getVC().powerOffVM(vm)); } _log.log(Level.INFO, "Waiting for completion..."); status.addStatus(blockOnVMTaskCompletion(powerOffTasks)); /* Currently blocking */ status.addStatus(testForPowerState(toPowerOff, false/*->powered-off*/)); _log.log(Level.INFO, "Done"); return status; } CompoundStatus shutdownGuests(VMDTO[] toShutDown) { CompoundStatus status = new CompoundStatus("shutdownGuests"); List<Future<VMDTO>> shutDownTasks = new ArrayList<Future<VMDTO>>(); List<VMDTO> shutDownNoTask = new ArrayList<VMDTO>(); for (VMDTO vm : toShutDown) { _log.log(Level.INFO, "Disabling VM "+vm._name+" ..."); Future<VMDTO> shutDownTask = getVC().shutdownGuest(vm); if (shutDownTask != null) { shutDownTasks.add(shutDownTask); } else { shutDownNoTask.add(vm); } } _log.log(Level.INFO, "Waiting for completion..."); if (shutDownNoTask.size() > 0) { // For guest shutdowns w/o tasks, check power status after delay time & force off if not off. try { Thread.sleep(shutdownGuestTimeOutMs); } catch (InterruptedException e) { _log.log(Level.WARNING, "Unexpected interruption waiting for guest shutdown ", e); } for (VMDTO vm : shutDownNoTask) { try { VMPowerState vmp = getVC().getPowerState(vm, true).get(); if (!vmp.equals(VMPowerState.POWERED_OFF)) { _log.log(Level.INFO, "Forcing power-off after guest shutdown of vm "+vm._name); shutDownTasks.add(getVC().powerOffVM(vm)); } } catch (Exception e) { String errorMsg = "Problem determining current power state of vm "+vm._name; _log.log(Level.SEVERE, errorMsg); status.registerTaskFailed(false, errorMsg); } } } if (shutDownTasks.size() > 0) { status.addStatus(blockOnVMTaskCompletion(shutDownTasks)); /* Currently blocking */ status.addStatus(testForPowerState(toShutDown, false/*->powered-off*/)); } _log.log(Level.INFO, "Done"); return status; } CompoundStatus testForPowerState(VMDTO[] vms, boolean assertEnabled){ CompoundStatus status = new CompoundStatus("testForPowerState"); VMPowerState successState = assertEnabled ? VMPowerState.POWERED_ON : VMPowerState.POWERED_OFF; for (VMDTO vm : vms) { /* "true" will refresh the powerstate and get() will block on getting the result */ try { VMPowerState vmp = getVC().getPowerState(vm, true).get(); if (!vmp.equals(successState)) { status.registerTaskFailed(false, "VM "+vm._name+" is not the correct power state"); } else { status.registerTaskSucceeded(); } } catch (Exception e) { status.registerTaskFailed(false, "Unexpected exception testing power states "+e.getMessage()); } } return status; } VCActions getVC() { return _vc; } }