/** * 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; import java.util.ArrayList; import org.inria.myriads.snoozecommon.communication.NetworkAddress; import org.inria.myriads.snoozecommon.communication.groupmanager.GroupManagerDescription; import org.inria.myriads.snoozecommon.communication.groupmanager.repository.GroupLeaderRepositoryInformation; import org.inria.myriads.snoozecommon.communication.groupmanager.repository.GroupManagerRepositoryInformation; import org.inria.myriads.snoozecommon.communication.localcontroller.AssignedGroupManager; import org.inria.myriads.snoozecommon.communication.localcontroller.LocalControllerDescription; import org.inria.myriads.snoozecommon.communication.localcontroller.LocalControllerList; import org.inria.myriads.snoozecommon.communication.rest.CommunicatorFactory; import org.inria.myriads.snoozecommon.communication.rest.api.GroupManagerAPI; import org.inria.myriads.snoozecommon.communication.virtualcluster.VirtualMachineMetaData; import org.inria.myriads.snoozecommon.communication.virtualcluster.discovery.VirtualMachineDiscoveryResponse; import org.inria.myriads.snoozecommon.communication.virtualcluster.migration.MigrationRequest; import org.inria.myriads.snoozecommon.communication.virtualcluster.requests.MetaDataRequest; import org.inria.myriads.snoozecommon.communication.virtualcluster.status.VirtualMachineStatus; import org.inria.myriads.snoozecommon.communication.virtualcluster.submission.VirtualClusterSubmissionRequest; import org.inria.myriads.snoozecommon.communication.virtualcluster.submission.VirtualClusterSubmissionResponse; import org.inria.myriads.snoozecommon.communication.virtualcluster.submission.VirtualMachineLocation; import org.inria.myriads.snoozecommon.communication.virtualcluster.submission.VirtualMachineSubmissionRequest; import org.inria.myriads.snoozecommon.communication.virtualcluster.submission.VirtualMachineSubmissionResponse; import org.inria.myriads.snoozecommon.communication.virtualmachine.ResizeRequest; import org.inria.myriads.snoozecommon.guard.Guard; import org.inria.myriads.snoozenode.database.api.GroupManagerRepository; import org.inria.myriads.snoozenode.groupmanager.statemachine.VirtualMachineCommand; import org.inria.myriads.snoozenode.groupmanager.virtualmachinediscovery.VirtualMachineDiscovery; import org.inria.myriads.snoozenode.message.ManagementMessage; import org.inria.myriads.snoozenode.message.ManagementMessageType; import org.inria.snoozenode.external.notifier.ExternalNotificationType; import org.restlet.resource.ServerResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Group manager resource class. * * @author Eugen Feller */ public final class GroupManagerResource extends ServerResource implements GroupManagerAPI { /** Define the logger. */ private static final Logger log_ = LoggerFactory.getLogger(GroupManagerResource.class); /** Define group manager backend. */ private GroupManagerBackend backend_; /** * Constructor. */ public GroupManagerResource() { log_.debug("Starting group manager resource"); backend_ = (GroupManagerBackend) getApplication().getContext().getAttributes().get("backend"); } /** * Dispatches the virtual cluster submission request. * (called by the client) * * @param virtualClusterDescription The virtual cluster description * @return The assigned task identifier */ @Override public String startVirtualCluster(VirtualClusterSubmissionRequest virtualClusterDescription) { Guard.check(virtualClusterDescription); log_.debug("Received virtual cluster start request"); if (!isGroupLeaderActive()) { return null; } String taskIdentifier = backend_.getGroupLeaderInit(). getVirtualClusterManager(). startVirtualClusterSubmission(virtualClusterDescription); log_.debug(String.format("Returning task identifier: %s", taskIdentifier)); return taskIdentifier; } /** * Handles the join request of a group manager. * (called by a group manager). * * @param groupManager The group manager description * @return true if everything ok, false otherwise */ @Override public boolean joinGroupLeader(GroupManagerDescription groupManager) { Guard.check(groupManager); log_.debug(String.format("Received join request from group manager %s at address %s", groupManager.getId(), groupManager.getListenSettings().getControlDataAddress().getAddress())); if (!isGroupLeaderActive()) { return false; } boolean isAdded = backend_.getGroupLeaderInit() .getRepository() .addGroupManagerDescription(groupManager); //backend group manager join return isAdded; } /** * Assign local controller to a group manager. * (called by the local controller). * * @param localControllerDescription The local controller description * @return The group manager description */ @Override public AssignedGroupManager assignLocalController(LocalControllerDescription localControllerDescription) { Guard.check(localControllerDescription); log_.debug(String.format("Received assign local controller request from %s at address %s" + " with capacity: %s", localControllerDescription.getId(), localControllerDescription.getControlDataAddress().getAddress(), localControllerDescription.getTotalCapacity())); if (!isGroupLeaderActive()) { return null; } AssignedGroupManager assignment = backend_.getGroupLeaderInit() .assignLocalController(localControllerDescription); log_.debug(String.format("Assigned group manager reference is: %s", assignment)); return assignment; } /** * Routine to discover the group manager hosting a virtual machine. * * @param virtualMachineId The virtual machine identifier * @return The discovery response */ @Override public VirtualMachineDiscoveryResponse discoverVirtualMachine(String virtualMachineId) { Guard.check(virtualMachineId); log_.debug(String.format("Starting virtual machine discovery for: %s", virtualMachineId)); if (!isGroupLeaderActive()) { return null; } VirtualMachineDiscovery discovery = backend_.getGroupLeaderInit().getVirtualMachineDiscovery(); VirtualMachineDiscoveryResponse discoveryResponse = discovery.startVirtualMachineDiscovery(virtualMachineId); return discoveryResponse; } /** * Routine the group leader information. * * @param numberOfMonitoringEntries The number of monitoring entries * @return The group leader repository information */ @Override public GroupLeaderRepositoryInformation getGroupLeaderRepositoryInformation(int numberOfMonitoringEntries) { log_.debug("Received a request to return group leader repository information"); if (!isGroupLeaderActive()) { return null; } GroupLeaderRepositoryInformation groupLeaderInformation = new GroupLeaderRepositoryInformation(); try { ArrayList<GroupManagerDescription> groupManagers = backend_.getGroupLeaderInit().getRepository().getGroupManagerDescriptions(numberOfMonitoringEntries); groupLeaderInformation.setGroupManagerDescriptions(groupManagers); } catch (Exception exception) { log_.error("Exception during group leader information retrieval", exception); } log_.debug(String.format("Returning reference: %s", groupLeaderInformation)); return groupLeaderInformation; } /** * Starts virtual machines on the group manager. * (called by group leader) * * @param submissionRequest The virtual machine submission * @return The task identifier */ @Override public String startVirtualMachines(VirtualMachineSubmissionRequest submissionRequest) { Guard.check(submissionRequest); log_.debug("Received start virtual machines command from group leader"); if (!isGroupManagerActive()) { return null; } String taskIdentifier = backend_.getGroupManagerInit() .getStateMachine() .startVirtualMachines(submissionRequest); return taskIdentifier; } /** * Routine to join the group manager. * (called by a local controller). * * @param localController The local controller description * @return true if everything ok, false otherwise */ @Override public boolean joinGroupManager(LocalControllerDescription localController) { Guard.check(localController); log_.debug(String.format("Received join request from %s local controller %s at address %s " + "with total capacity: %s", localController.getStatus(), localController.getId(), localController.getControlDataAddress().getAddress(), localController.getTotalCapacity())); if (!isGroupManagerActive()) { return false; } boolean isAdded = backend_.getGroupManagerInit() .getRepository() .addLocalControllerDescription(localController); return isAdded; } /** * Routine to suspend a virtual machine. * * @param location The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean suspendVirtualMachine(VirtualMachineLocation location) { Guard.check(location); log_.debug(String.format("Received virtual machine suspend request for: %s", location.getVirtualMachineId())); if (!isGroupManagerActive()) { return false; } boolean isSuspended = backend_.getGroupManagerInit() .getStateMachine() .controlVirtualMachine(VirtualMachineCommand.SUSPEND, location); return isSuspended; } /** * Routine to resume a virtual machine. * * @param location The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean resumeVirtualMachine(VirtualMachineLocation location) { Guard.check(location); log_.debug(String.format("Received virtual machine resume request for: %s", location.getVirtualMachineId())); if (!isGroupManagerActive()) { return false; } boolean isResumed = backend_.getGroupManagerInit() .getStateMachine() .controlVirtualMachine(VirtualMachineCommand.RESUME, location); return isResumed; } /** * Routine to shutdown a virtual machine. * * @param location The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean shutdownVirtualMachine(VirtualMachineLocation location) { Guard.check(location); log_.debug(String.format("Received virtual machine shutdown request for: %s", location.getVirtualMachineId())); if (!isGroupManagerActive()) { return false; } boolean isShutdown = backend_.getGroupManagerInit() .getStateMachine() .controlVirtualMachine(VirtualMachineCommand.SHUTDOWN, location); return isShutdown; } /** * Routine to reboot a virtual machine. * * @param location The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean rebootVirtualMachine(VirtualMachineLocation location) { Guard.check(location); log_.debug(String.format("Received virtual machine reboot request for: %s", location.getVirtualMachineId())); if (!isGroupManagerActive()) { return false; } boolean isRebooted = backend_.getGroupManagerInit() .getStateMachine() .controlVirtualMachine(VirtualMachineCommand.REBOOT, location); return isRebooted; } /** * Routine to shutdown a virtual machine. * * @param location The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean destroyVirtualMachine(VirtualMachineLocation location) { Guard.check(location); log_.debug(String.format("Received virtual machine destroy request for: %s on %s", location.getVirtualMachineId(), location.getLocalControllerId())); if (!isGroupManagerActive()) { return false; } boolean isDestroyed = backend_.getGroupManagerInit() .getStateMachine() .controlVirtualMachine(VirtualMachineCommand.DESTROY, location); return isDestroyed; } /** * Checks if a virtual machine is active on all local controller. * * @param virtualMachineId The virtual machine identifier * @return The local controller identifier */ @Override public String searchVirtualMachine(String virtualMachineId) { Guard.check(virtualMachineId); log_.debug(String.format("Checking if virtual machine %s is hosted on any local controller", virtualMachineId)); if (!isGroupManagerActive()) { return null; } String localControllerId = backend_.getGroupManagerInit() .getRepository() .searchVirtualMachine(virtualMachineId); return localControllerId; } /** * Checks if a virtual machine is active a particular local controller. * * @param location The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean hasVirtualMachine(VirtualMachineLocation location) { Guard.check(location); log_.debug(String.format("Checking if virtual machine %s is hosted on local controller %s", location.getVirtualMachineId(), location.getLocalControllerId())); if (!isGroupManagerActive()) { return false; } boolean hasVirtualMachine = backend_.getGroupManagerInit() .getRepository() .hasVirtualMachine(location); return hasVirtualMachine; } /** * Checks if a virtual machine is active a particular local controller. * (energy management) * * @deprecated * @param localControllerAddress The virtual machine location * @return true if everything ok, false otherwise * */ @Override public String hasLocalController(NetworkAddress localControllerAddress) { Guard.check(localControllerAddress); log_.debug(String.format("Checking if information for local controller %s: %s exists", localControllerAddress.getAddress(), localControllerAddress.getPort())); if (!isGroupManagerActive()) { return null; } String hasLocalControllerId = backend_.getGroupManagerInit() .getRepository() .hasLocalController(localControllerAddress); return hasLocalControllerId; } /** * Routine to get virtual machine information. * * @param request The meta data request * @return The virtual machine meta data */ @Override public VirtualMachineMetaData getVirtualMachineMetaData(MetaDataRequest request) { Guard.check(request); String virtualMachineId = request.getVirtualMachineLocation().getVirtualMachineId(); log_.debug(String.format("Received virtual machine information request from client for: %s", virtualMachineId)); if (!isGroupManagerActive()) { return null; } VirtualMachineLocation location = request.getVirtualMachineLocation(); int numberOfMonitoringEntries = request.getNumberOfMonitoringEntries(); GroupManagerRepository repository = backend_.getGroupManagerInit().getRepository(); VirtualMachineMetaData virtualMachine = repository.getVirtualMachineMetaData(location, numberOfMonitoringEntries); if (virtualMachine == null) { log_.debug("No meta data available for this virtual machine!"); virtualMachine = new VirtualMachineMetaData(); virtualMachine.getVirtualMachineLocation().setVirtualMachineId(virtualMachineId); virtualMachine.setStatus(VirtualMachineStatus.OFFLINE); return virtualMachine; } return virtualMachine; } @Override public GroupManagerDescription getGroupManagerDescription(String groupManagerId) { log_.debug("Received a request to return a group manager description"); if (!isGroupLeaderActive()) { return null; } return backend_.getGroupLeaderInit().getRepository().getGroupManagerDescription(groupManagerId, 0); } /** * Return the group leader information. * * @param numberOfMonitoringEntries The number of monitoring entries * @return The group manager repository information */ @Override public GroupManagerRepositoryInformation getGroupManagerRepositoryInformation(int numberOfMonitoringEntries) { log_.debug("Received a request to return group manager repository information"); if (!isGroupManagerActive()) { return null; } GroupManagerRepositoryInformation groupManagerInformation = new GroupManagerRepositoryInformation(); ArrayList<LocalControllerDescription> localControllers = backend_.getGroupManagerInit().getRepository().getLocalControllerDescriptions(numberOfMonitoringEntries, false, true); groupManagerInformation.setLocalControllerDescriptions(localControllers); log_.debug(String.format("Returning reference: %s, number of local controllers: %d", groupManagerInformation, groupManagerInformation.getLocalControllerDescriptions().size())); return groupManagerInformation; } /** * Checks group manager initialization. * * @return true if initialized, false otherwise */ private boolean isGroupManagerActive() { if (backend_ == null) { log_.debug("Backend is not initialized yet!"); return false; } if (backend_.getGroupManagerInit() == null) { log_.debug("Group manager logic is not available yet!"); return false; } return true; } /** * Checks group leader initialization. * * @return true if initialized, false otherwise */ private boolean isGroupLeaderActive() { if (backend_ == null) { log_.debug("Backend is not initialized yet!"); return false; } if (backend_.getGroupLeaderInit() == null) { log_.debug("Group leader logic is not available yet!"); return false; } return true; } /** * Suspends the energy saver. * * @return The group manager repository information */ @Override public boolean suspendEnergySaver() { log_.debug("Received a request to suspend the energy saver"); if (!isGroupManagerActive()) { return false; } backend_.getGroupManagerInit().getEnergySaver().setSuspend(); return true; } /** * Resumes the energy saver. * * @return The group manager repository information */ @Override public boolean resumeEnergySaver() { log_.debug("Received a request to resume the energy saver"); if (!isGroupManagerActive()) { return false; } backend_.getGroupManagerInit().getEnergySaver().wakeup(); log_.debug("Energy saver wakeup done!"); return true; } /** * Drops virtual machine meta data. * * @param virtualMachineLocation The virtual machine location * @return true if everything ok, false otherwise */ @Override public boolean dropVirtualMachineMetaData(VirtualMachineLocation virtualMachineLocation) { Guard.check(virtualMachineLocation); if (!isGroupManagerActive()) { return false; } boolean isDropped = backend_.getGroupManagerInit() .getRepository() .dropVirtualMachineData(virtualMachineLocation); backend_.getGroupManagerInit().getExternalNotifier().send( ExternalNotificationType.MANAGEMENT, new ManagementMessage(ManagementMessageType.PROCESSED, null), virtualMachineLocation.getGroupManagerId() + "." + virtualMachineLocation.getLocalControllerId() + "." + virtualMachineLocation.getVirtualMachineId() + "." + "DROP" ); return isDropped; } /** * Returns the virtual machine submission finish. * * @param taskIdentifier The virtual machine task identifier * @return The virtual machine submission response */ @Override public VirtualMachineSubmissionResponse getVirtualMachineSubmissionResponse(String taskIdentifier) { Guard.check(taskIdentifier); log_.debug(String.format("Received a request for virtual machine %s response lookup", taskIdentifier)); if (!isGroupManagerActive()) { return null; } VirtualMachineSubmissionResponse submissionResponse = backend_.getGroupManagerInit() .getStateMachine() .getVirtualMachineSubmissionResponse(taskIdentifier); log_.debug(String.format("Returning virtual machine response: %s", submissionResponse)); return submissionResponse; } /** * Returns the virtual cluster response if available. * * @param taskIdentifier The task identifier * @return The virtual cluster response */ @Override public VirtualClusterSubmissionResponse getVirtualClusterResponse(String taskIdentifier) { Guard.check(taskIdentifier); log_.debug(String.format("Received a request for virtual cluster %s response lookup", taskIdentifier)); if (!isGroupLeaderActive()) { return null; } VirtualClusterSubmissionResponse respomse = backend_.getGroupLeaderInit() .getVirtualClusterManager() .getVirtualClusterResponse(taskIdentifier); log_.debug(String.format("Returning virtual cluster response: %s", respomse)); return respomse; } /** * * Gets the list of local controllers. * * @return The local controller list */ public LocalControllerList getLocalControllerList() { log_.debug(String.format("Received a request for local controller list")); if (!isGroupLeaderActive()) { return null; } ArrayList<LocalControllerDescription> localControllers = backend_.getGroupLeaderInit() .getRepository() .getLocalControllerList(); LocalControllerList localControllerList = new LocalControllerList(localControllers); return localControllerList; } /** * Migrate a virtual machine. * (call by the client) * * @param migrationRequest The client migration Request * @return true if ok false otherwise */ public boolean migrateVirtualMachine(MigrationRequest migrationRequest) { Guard.check(migrationRequest); if (!isGroupManagerActive()) { // Group Leader Logic VirtualMachineLocation oldLocation = migrationRequest.getSourceVirtualMachineLocation(); VirtualMachineLocation newLocation = migrationRequest.getDestinationVirtualMachineLocation(); boolean updated = true; updated = backend_.getGroupLeaderInit().getRepository().updateLocation(oldLocation); if (!updated) { return false; } updated = backend_.getGroupLeaderInit().getRepository().updateLocation(newLocation); if (!updated) { return false; } LocalControllerDescription localController = backend_ .getGroupLeaderInit() .getRepository() .getLocalControllerDescription(newLocation.getLocalControllerId()); migrationRequest.setDestinationHypervisorSettings(localController.getHypervisorSettings()); // call to the gm source to migrate the vm. NetworkAddress groupManagerSource = oldLocation.getGroupManagerControlDataAddress(); GroupManagerAPI communicator = CommunicatorFactory.newGroupManagerCommunicator(groupManagerSource); communicator.migrateVirtualMachine(migrationRequest); return true; } else { // Group Manager Logic boolean isMigrated = backend_.getGroupManagerInit() .getStateMachine().startMigration(migrationRequest); return isMigrated; } } /** * Resize a virtual machine. * (call by the client) * * @param resizeRequest The client resize Request * @return true if ok false otherwise */ public VirtualMachineMetaData resizeVirtualMachine(ResizeRequest resizeRequest) { Guard.check(resizeRequest); if (!isGroupManagerActive()) { return null; } VirtualMachineMetaData newVirtualMachineMetaData = backend_.getGroupManagerInit() .getStateMachine() .resizeVirtualMachine(resizeRequest); return newVirtualMachineMetaData; } @Override public boolean addVirtualMachineAfterMigration(VirtualMachineMetaData virtualMachine) { Guard.check(virtualMachine); if (!isGroupManagerActive()) { return false; } boolean isUpdated = backend_.getGroupManagerInit().getRepository().addVirtualMachine(virtualMachine); return isUpdated; } @Override public LocalControllerDescription getLocalControllerDescription(String localControllerId) { log_.debug("Received a request to return a local controller description"); if (!isGroupManagerActive()) { return null; } LocalControllerDescription localController = backend_ .getGroupManagerInit() .getRepository() .getLocalControllerDescription(localControllerId, 0, false); return localController; } @Override public boolean startReconfiguration() { log_.debug("Received a request to start a reconfiguration"); if (!isGroupManagerActive()) { return false; } boolean isStarted = backend_.getGroupManagerInit().getStateMachine().startReconfiguration(); return isStarted; } }