/** * Abiquo community edition * cloud management application for hybrid clouds * Copyright (C) 2008-2010 - Abiquo Holdings S.L. * * This application is free software; you can redistribute it and/or * modify it under the terms of the GNU LESSER GENERAL PUBLIC * LICENSE as published by the Free Software Foundation under * version 3 of the License * * This software 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 * LESSER GENERAL PUBLIC LICENSE v.3 for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package com.abiquo.vsm.monitor; import java.io.IOException; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.abiquo.vsm.VSMManager; import com.abiquo.vsm.events.VMEvent; import com.abiquo.vsm.events.VMEventType; import com.abiquo.vsm.exception.MonitorException; import com.abiquo.vsm.model.PhysicalMachine; import com.abiquo.vsm.model.VirtualMachine; import com.abiquo.vsm.redis.dao.RedisDao; import com.abiquo.vsm.redis.dao.RedisDaoFactory; import com.abiquo.vsm.redis.pubsub.RedisPublisher; /** * Base class for all monitor implementations. * * @author ibarrera */ public abstract class AbstractMonitor { /** The logger. */ private static final Logger LOGGER = LoggerFactory.getLogger(AbstractMonitor.class); /** Event notifier used to push events to Redis. */ private RedisPublisher redisPublisher; /** List of monitored physical machine addresses. */ protected List<String> monitoredMachines; /** The dao used to access stored data. */ private RedisDao dao; protected String uuid; /** * Creates the monitor. */ public AbstractMonitor() { String redisHost = VSMManager.getInstance().getRedisHost(); int redisPort = VSMManager.getInstance().getRedisPort(); redisPublisher = new RedisPublisher(redisHost, redisPort); monitoredMachines = Collections.synchronizedList(new LinkedList<String>()); dao = RedisDaoFactory.getInstance(); uuid = UUID.randomUUID().toString(); LOGGER.debug("New monitor with UUID " + uuid + " created."); } /** * Start monitoring the target physical machine. */ public abstract void start(); /** * Stop monitoring the target physical machine and shutdown the monitor. */ public abstract void shutdown(); /** * Publish the current state of the given virtual machine. * * @param physicalMachineAddress The monitored physical machine where the virtual machine is * deployed. * @param virtualMachineName The name of the virtual machine. * @throws MonitorException If an error occurs while getting the state of the virtual machine. */ public void publishState(final String physicalMachineAddress, final String virtualMachineName) throws MonitorException { invalidateLastKnownState(physicalMachineAddress, virtualMachineName); } /** * Invalidates the last known state for a given virtual machine. * * @param physicalMachineAddress The monitored physical machine where the virtual machine is * deployed. * @param virtualMachineName The name of the virtual machine. * @throws MonitorException If an error occurs while invalidating the last known state of the * virtual machine. */ public void invalidateLastKnownState(final String physicalMachineAddress, final String virtualMachineName) throws MonitorException { // Update the last known state to UNKNOWN in order to force the event notification VirtualMachine virtualMachine = dao.findVirtualMachineByName(virtualMachineName); if (virtualMachine != null) { virtualMachine.setLastKnownState(VMEventType.UNKNOWN.name()); dao.save(virtualMachine); } } /** * Return the maximum number of hypervisors that can be monitored by this monitor instance. * * @return The maximum number of hypervisors that can be monitored by this monitor instance. */ public abstract int getMaxNumberOfHypervisors(); /** * Check if there are available slots to monitor more hypervisors. * * @return Boolean indicating if there are available slots to monitor more hypervisors. */ public boolean hasAvailableSlots() { synchronized (monitoredMachines) { int max = getMaxNumberOfHypervisors(); return max == 0 ? true : max > monitoredMachines.size(); } } /** * Add a physical machine to be monitored. * * @param physicalMachineAddress The physical machine address to be monitored. * @throws MonitorException If the physical machine can not be added. */ public void addPhysicalMachine(final String physicalMachineAddress) throws MonitorException { synchronized (monitoredMachines) { monitoredMachines.add(physicalMachineAddress); } LOGGER.debug("Added {} to the list of monitored machines of monitor {}", physicalMachineAddress, uuid); } /** * Remove a physical machine from the monitored machines list. * * @param physicalMachineAddress The physical machine to remove from the monitored machines * list. * @throws MonitorException If the physical machine can not be removed. */ public void removePhysicalMachine(final String physicalMachineAddress) throws MonitorException { synchronized (monitoredMachines) { monitoredMachines.remove(physicalMachineAddress); LOGGER.debug("Removed {} from the list of monitored machines of monitor {}", physicalMachineAddress, uuid); if (monitoredMachines.isEmpty()) { LOGGER.info("There are no more machines to monitor. Shutting down monitor {}.", uuid); shutdown(); } } } /** * Check if the current monitor is monitoring the given physical machine. * * @param physicalMachineAddress The physical machine. * @return Boolean indicating if the current monitor is monitoring the given physical machine. */ public boolean monitors(final String physicalMachineAddress) { synchronized (monitoredMachines) { return monitoredMachines.contains(physicalMachineAddress); } } /** * Notifies an event that has been fired in a virtual machine. * * @param event The event to propagate. */ public void notify(final VMEvent event) { try { LOGGER.trace("Received event from monitor {}: {}", uuid, event.toString()); redisPublisher.publishEvent(event); } catch (IOException ex) { LOGGER.error("Unable to notify event: " + event.toString(), ex); } } /** * Gets the monitored machine list * * @return the list of monitored machines */ public List<String> getMonitoredMachines() { return monitoredMachines; } /** * Get the given physical machine from the database. * * @param physicalMachineAddress The address of the physical machine. * @return The physical machine. * @throws MonitorException If the physical machine is not found. */ protected PhysicalMachine getPhysicalMachine(final String physicalMachineAddress) throws MonitorException { PhysicalMachine pm = dao.findPhysicalMachineByAddress(physicalMachineAddress); if (pm == null) { throw new MonitorException("The physical machine at " + physicalMachineAddress + " is not being monitored"); } return pm; } }