/** * Copyright (C) 2010-2013 Eugen Feller, INRIA <eugen.feller@inria.fr> * * This file is part of Snooze, a scalable, autonomic, and * energy-aware virtual machine (VM) management framework. * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see <http://www.gnu.org/licenses>. */ package org.inria.myriads.snoozenode.groupmanager.anomaly; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.inria.myriads.snoozecommon.communication.localcontroller.LocalControllerDescription; import org.inria.myriads.snoozecommon.communication.localcontroller.LocalControllerStatus; import org.inria.myriads.snoozecommon.communication.virtualcluster.VirtualMachineMetaData; import org.inria.myriads.snoozecommon.guard.Guard; import org.inria.myriads.snoozenode.configurator.scheduler.RelocationSettings; import org.inria.myriads.snoozenode.database.api.GroupManagerRepository; import org.inria.myriads.snoozenode.exception.AnomalyResolverException; import org.inria.myriads.snoozenode.groupmanager.estimator.ResourceDemandEstimator; import org.inria.myriads.snoozenode.groupmanager.managerpolicies.GroupManagerPolicyFactory; import org.inria.myriads.snoozenode.groupmanager.managerpolicies.reconfiguration.ReconfigurationPlan; import org.inria.myriads.snoozenode.groupmanager.managerpolicies.relocation.VirtualMachineRelocation; import org.inria.myriads.snoozenode.groupmanager.migration.MigrationPlanEnforcer; import org.inria.myriads.snoozenode.groupmanager.migration.listener.MigrationPlanListener; import org.inria.myriads.snoozenode.groupmanager.statemachine.api.StateMachine; import org.inria.myriads.snoozenode.localcontroller.monitoring.enums.LocalControllerState; import org.inria.myriads.snoozenode.message.SystemMessage; import org.inria.myriads.snoozenode.message.SystemMessageType; import org.inria.myriads.snoozenode.util.ExternalNotifierUtils; import org.inria.snoozenode.external.notifier.ExternalNotificationType; import org.inria.snoozenode.external.notifier.ExternalNotifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Anomaly resolver. * * @author Eugen Feller */ public final class AnomalyResolver implements MigrationPlanListener { /** Define the logger. */ private static final Logger log_ = LoggerFactory.getLogger(AnomalyResolver.class); /** Overload relocation policy. */ private VirtualMachineRelocation overloadRelocationPolicy_; /** Underload relocation policy. */ private VirtualMachineRelocation underloadRelocationPolicy_; /** The group manager repository. */ private GroupManagerRepository groupManagerRepository_; /** Anomaly local controller. */ private LocalControllerDescription anomalyLocalController_; /** State machine. */ private StateMachine stateMachine_; /** Number of monitoring entries. */ private int numberOfMonitoringEntries_; /** External Notifier.*/ private ExternalNotifier externalNotifier_; /** * Constructor. * * @param relocationPolicies The relocation parameters * @param resourceDemandEstimator The resource demand estimator * @param groupManagerRepository The group manager repository * @param stateMachine The state machine * @param externalNotifier The external notifier */ public AnomalyResolver(RelocationSettings relocationPolicies, ResourceDemandEstimator resourceDemandEstimator, GroupManagerRepository groupManagerRepository, StateMachine stateMachine, ExternalNotifier externalNotifier ) { Guard.check(relocationPolicies, resourceDemandEstimator, groupManagerRepository, stateMachine); log_.debug("Initializing the anomaly resolver"); overloadRelocationPolicy_ = GroupManagerPolicyFactory.newVirtualMachineRelocation(relocationPolicies.getOverloadPolicy(), resourceDemandEstimator); underloadRelocationPolicy_ = GroupManagerPolicyFactory.newVirtualMachineRelocation(relocationPolicies.getUnderloadPolicy(), resourceDemandEstimator); numberOfMonitoringEntries_ = resourceDemandEstimator.getNumberOfMonitoringEntries(); groupManagerRepository_ = groupManagerRepository; stateMachine_ = stateMachine; externalNotifier_ = externalNotifier; } /** * Computes the relocation plan. * * @param localControllerState The local controller state * @param anomalyLocalController The anomaly local controller description * @param destinationLocalControllers The destination local controller descriptions * @return The migration plan */ private ReconfigurationPlan computeRelocationPlan(LocalControllerState localControllerState, LocalControllerDescription anomalyLocalController, List<LocalControllerDescription> destinationLocalControllers) { Guard.check(localControllerState, anomalyLocalController, destinationLocalControllers); log_.debug(String.format("Computing migration plan for %s local controller: %s", localControllerState, anomalyLocalController.getId())); ReconfigurationPlan relocationPlan = null; switch (localControllerState) { case OVERLOADED: relocationPlan = overloadRelocationPolicy_.relocateVirtualMachines(anomalyLocalController, destinationLocalControllers); break; case UNDERLOADED: relocationPlan = underloadRelocationPolicy_.relocateVirtualMachines(anomalyLocalController, destinationLocalControllers); break; default: log_.error(String.format("Unsupported state: %s", localControllerState)); break; } return relocationPlan; } /** * Returns the destination local controller descriptions. * * @param state The lcoal controller state * @return The local controller descriptions */ private List<LocalControllerDescription> getDestinationLocalControllers(LocalControllerState state) { log_.debug(String.format("Returning %s local controllers", state)); List<LocalControllerDescription> destination; if (state.equals(LocalControllerState.OVERLOADED)) { log_.debug("Getting all local controllers (including PASSIVE)"); destination = groupManagerRepository_.getLocalControllerDescriptions(numberOfMonitoringEntries_, false, true); return destination; } log_.debug("Getting all local controllers (excluding PASSIVE)"); destination = groupManagerRepository_.getLocalControllerDescriptions(numberOfMonitoringEntries_, true, true); return destination; } /** * Called to resolve anomaly. * * @param localControllerId The anomaly local controller identifier * @param state The local controller state * @throws Exception The exception */ public synchronized void resolveAnomaly(String localControllerId, LocalControllerState state) throws Exception { Guard.check(localControllerId, state); log_.debug("Starting anomaly resolution"); LocalControllerDescription anomalyLocalController = groupManagerRepository_.getLocalControllerDescription(localControllerId, numberOfMonitoringEntries_, true); ExternalNotifierUtils.send( externalNotifier_, ExternalNotificationType.SYSTEM, new SystemMessage(SystemMessageType.LC_ANOMALY, anomalyLocalController), "groupmanager." + groupManagerRepository_.getGroupManagerId() ); if (anomalyLocalController == null) { throw new AnomalyResolverException("Local controller description is not available!"); } List<LocalControllerDescription> destinationControllers = getDestinationLocalControllers(state); if (destinationControllers == null) { throw new AnomalyResolverException("Destination local controller descriptions are not available!"); } ReconfigurationPlan migrationPlan = computeRelocationPlan(state, anomalyLocalController, destinationControllers); if (migrationPlan == null) { throw new AnomalyResolverException("Migration plan is not available!"); } if (migrationPlan.getMapping().size() > 0) { log_.debug(String.format("%s relocation started!", state)); } List<LocalControllerDescription> passiveLocalControllers = getPassiveLocalControllers(migrationPlan); if (passiveLocalControllers.size() > 0) { log_.debug("Migration plan has PASSIVE local controllers!"); boolean isWokenUp = stateMachine_.onWakeupLocalControllers(passiveLocalControllers); if (!isWokenUp) { throw new AnomalyResolverException("Failed to wakeup local controllers!"); } } if (state.equals(LocalControllerState.UNDERLOADED)) { anomalyLocalController_ = anomalyLocalController; } MigrationPlanEnforcer migrationPlanExecutor = new MigrationPlanEnforcer(groupManagerRepository_, this, externalNotifier_); migrationPlanExecutor.enforceMigrationPlan(migrationPlan); } /** * Called when migration plan was enforced. */ public void onMigrationPlanEnforced() { log_.debug("Entering on migration plan enforced!"); stateMachine_.onAnomalyResolved(anomalyLocalController_); } /** * Checking migration plan for passive local controllers. * * @param migrationPlan The migration plan * @return The list of passive local controllers */ private List<LocalControllerDescription> getPassiveLocalControllers(ReconfigurationPlan migrationPlan) { log_.debug("Checking for passive local controllers in the migration plan"); Map<VirtualMachineMetaData, LocalControllerDescription> mapping = migrationPlan.getMapping(); Map<String, LocalControllerDescription> passiveControllers = new HashMap<String, LocalControllerDescription>(); for (LocalControllerDescription localController : mapping.values()) { String localControllerId = localController.getId(); LocalControllerStatus status = localController.getStatus(); if (status.equals(LocalControllerStatus.PASSIVE)) { passiveControllers.put(localControllerId, localController); } } List<LocalControllerDescription> localControllers = new ArrayList<LocalControllerDescription>(passiveControllers.values()); return localControllers; } }