/**
* 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.bootstrap;
import java.util.ArrayList;
import java.util.HashMap;
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.LocalControllerDescription;
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.submission.VirtualMachineLocation;
import org.inria.myriads.snoozecommon.guard.Guard;
import org.inria.myriads.snoozenode.configurator.api.NodeConfiguration;
import org.inria.myriads.snoozenode.configurator.database.DatabaseSettings;
import org.inria.myriads.snoozenode.database.DatabaseFactory;
import org.inria.myriads.snoozenode.database.api.BootstrapRepository;
import org.inria.myriads.snoozenode.groupmanager.statemachine.VirtualMachineCommand;
import org.inria.myriads.snoozenode.heartbeat.HeartbeatFactory;
import org.inria.myriads.snoozenode.heartbeat.listener.HeartbeatListener;
import org.inria.myriads.snoozenode.heartbeat.message.HeartbeatMessage;
import org.inria.myriads.snoozenode.util.ManagementUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Bootstrap backend logic.
*
* @author Eugen Feller
*/
public final class BootstrapBackend
implements HeartbeatListener
{
/** Define the logger. */
private static final Logger log_ = LoggerFactory.getLogger(BootstrapBackend.class);
/** The group leader description. */
private GroupManagerDescription groupLeaderDescription_;
/** The node configuration.*/
private NodeConfiguration nodeConfiguration_;
/** The repository.*/
private BootstrapRepository repository_;
/** Track backend activity.*/
private boolean isActive_;
/**
* Bootstrap backend constructor.
*
* @param nodeParameters The node parameters
* @throws Exception Exception
*/
public BootstrapBackend(NodeConfiguration nodeParameters)
throws Exception
{
Guard.check(nodeParameters);
log_.debug("Starting bootstrap backend");
nodeConfiguration_ = nodeParameters;
NetworkAddress address = nodeParameters.getNetworking().getMulticast().getGroupLeaderHeartbeatAddress();
int heartbeatTimeout = nodeParameters.getFaultTolerance().getHeartbeat().getTimeout();
new Thread(HeartbeatFactory.newHeartbeatMulticastListener(address,
heartbeatTimeout,
this),
"HeartBeatListener"
).start();
initializeRepository();
isActive_ = true;
}
/**
*
* Initialize the backend repository (read only).
*
*/
private void initializeRepository()
{
DatabaseSettings settings = nodeConfiguration_.getDatabase();
repository_ = DatabaseFactory.newBootstrapRepository(settings);
}
/**
* Return current group leader.
*
* @return Group leader information
*/
public GroupManagerDescription getGroupLeaderDescription()
{
return groupLeaderDescription_;
}
/**
* Called by the heartbeat listener upon heartbeat arrival.
*
* @param heartbeatMessage Heartbeat message
*/
public void onHeartbeatArrival(HeartbeatMessage heartbeatMessage)
{
Guard.check(heartbeatMessage);
log_.debug(String.format("Received group leader heartbeat message from: %s, " +
"listen port: %d, " +
"monitoring data port: %d",
heartbeatMessage.getListenSettings().getControlDataAddress().getAddress(),
heartbeatMessage.getListenSettings().getControlDataAddress().getPort(),
heartbeatMessage.getListenSettings().getMonitoringDataAddress().getPort()));
if (groupLeaderDescription_ == null ||
groupLeaderDescription_.getId().compareTo(heartbeatMessage.getId()) != 0)
{
log_.debug("Updating group leader information");
groupLeaderDescription_ = ManagementUtils.createGroupLeaderDescriptionFromHeartbeat(heartbeatMessage);
}
}
/**
* Called by the heartbeat listener upon heartbeat failure.
*/
public void onHeartbeatFailure()
{
log_.debug("Group leader does not exist or has failed");
if (groupLeaderDescription_ != null)
{
groupLeaderDescription_ = null;
}
}
/**
*
* Gets the complete hierarchy of the snooze system.
*
* @return The group leader repository completed with localcontrollers informations.
*/
public GroupLeaderRepositoryInformation getCompleteHierarchy()
{
log_.debug("Starting the hierarchy building");
NetworkAddress groupLeaderAddress = groupLeaderDescription_.getListenSettings().getControlDataAddress();
GroupLeaderRepositoryInformation groupLeaderInformation =
getGroupLeaderRepositoryInformation(groupLeaderAddress, 0);
GroupLeaderRepositoryInformation hierarchy = new GroupLeaderRepositoryInformation();
ArrayList<GroupManagerDescription> groupManagers = groupLeaderInformation.getGroupManagerDescriptions();
hierarchy.setGroupManagerDescriptions(groupManagers);
int i = 0;
for (GroupManagerDescription groupManager : groupManagers)
{
NetworkAddress address = groupManager.getListenSettings().getControlDataAddress();
GroupManagerRepositoryInformation information = getGroupManagerRepositoryInformations(address, 0);
HashMap<String, LocalControllerDescription> localControllers =
new HashMap<String, LocalControllerDescription>();
for (LocalControllerDescription localController : information.getLocalControllerDescriptions())
{
localControllers.put(localController.getId(), localController);
}
hierarchy.getGroupManagerDescriptions().get(i).setLocalControllers(localControllers);
i++;
}
return hierarchy;
}
/**
*
* Gets the group leader repository informations.
*
* @param groupLeaderAddress The group leader address
* @param numberOfBacklogEntries The number of log wanted
* @return The group leader repository
*/
public GroupLeaderRepositoryInformation getGroupLeaderRepositoryInformation(
NetworkAddress groupLeaderAddress,
int numberOfBacklogEntries)
{
Guard.check(groupLeaderAddress);
log_.info(String.format("Getting group leader repository information"));
GroupManagerAPI groupLeaderCommunicator =
CommunicatorFactory.newGroupManagerCommunicator(groupLeaderAddress);
GroupLeaderRepositoryInformation information =
groupLeaderCommunicator.getGroupLeaderRepositoryInformation(numberOfBacklogEntries);
return information;
}
/**
*
* Gets the group manager repository informations.
*
* @param groupManagerAddress The group manager address
* @param numberOfBacklogEntries The number of logs wanted
* @return The group manager repository
*/
public GroupManagerRepositoryInformation getGroupManagerRepositoryInformations(
NetworkAddress groupManagerAddress,
int numberOfBacklogEntries)
{
Guard.check(groupManagerAddress);
log_.info(String.format("Getting group manager repository informations"));
GroupManagerAPI groupManagerCommunicator =
CommunicatorFactory.newGroupManagerCommunicator(groupManagerAddress);
GroupManagerRepositoryInformation information =
groupManagerCommunicator.getGroupManagerRepositoryInformation(numberOfBacklogEntries);
return information;
}
/**
*
* Sends a command to a virtual machine.
*
* @param command command to send.
* @param virtualMachineId virtualMachine Id.
* @return true iff everything is ok.
*/
public synchronized boolean commandVirtualMachine(VirtualMachineCommand command, String virtualMachineId)
{
VirtualMachineMetaData virtualMachine =
getRepository().getVirtualMachineMetaData(virtualMachineId, 0, getGroupLeaderDescription());
if (virtualMachine == null)
{
log_.debug(String.format("Virtual Machine %s not found in the system", virtualMachineId));
return false;
}
VirtualMachineLocation location = virtualMachine.getVirtualMachineLocation();
NetworkAddress groupManagerAddress = location.getGroupManagerControlDataAddress();
GroupManagerAPI groupManagerCommunicator = CommunicatorFactory.newGroupManagerCommunicator(groupManagerAddress);
boolean isProcessed = false;
switch(command)
{
case DESTROY:
isProcessed = groupManagerCommunicator.destroyVirtualMachine(location);
break;
case REBOOT :
isProcessed = groupManagerCommunicator.rebootVirtualMachine(location);
break;
case SUSPEND :
isProcessed = groupManagerCommunicator.suspendVirtualMachine(location);
break;
case RESUME :
isProcessed = groupManagerCommunicator.resumeVirtualMachine(location);
break;
case SHUTDOWN :
isProcessed = groupManagerCommunicator.shutdownVirtualMachine(location);
break;
default :
log_.debug("Unknown command provided");
}
return isProcessed;
}
/**
*
* Gets the bootstrap repository.
*
* @return The repository.
*/
public BootstrapRepository getRepository()
{
return repository_;
}
/**
*
* checks if backend is active.
*
* @return isActive
*/
public boolean isActive()
{
return isActive_;
}
}