diff --git a/server/src/com/cloud/resource/ResourceLifeCycleListener.java b/server/src/com/cloud/resource/ResourceLifeCycleListener.java deleted file mode 100644 index 62d88cd6062..00000000000 --- a/server/src/com/cloud/resource/ResourceLifeCycleListener.java +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. - * - * This software is licensed under the GNU General Public License v3 or later. - * - * It 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 3 of the License, or 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 . - * - */ -package com.cloud.resource; - -import com.cloud.agent.api.StartupCommand; -import com.cloud.host.Host; -import com.cloud.host.HostVO; - -/** - * Listener registered with the ResourceManager if you want to be informed - * of a certain type of host's life cycles. - * - */ -public interface ResourceLifeCycleListener { - /** - * @return the type of resource this listener can process. - */ - Host.Type getType(); - - void add(HostVO host, StartupCommand cmd, boolean created); - - /** - * Put the resource into maintenance mode. - */ - void maintain(HostVO host, boolean force); - - void removed(HostVO host, boolean force); - - void enable(HostVO host); - - void disable(HostVO host); - -} diff --git a/server/src/com/cloud/resource/ResourceManager.java b/server/src/com/cloud/resource/ResourceManager.java old mode 100644 new mode 100755 index cc27eaf5d1f..526c22bb642 --- a/server/src/com/cloud/resource/ResourceManager.java +++ b/server/src/com/cloud/resource/ResourceManager.java @@ -28,8 +28,10 @@ public interface ResourceManager { * Register a listener for different types of resource life cycle events. * There can only be one type of listener per type of host. * - * @param type the resource type the listener is responsible to. + * @param Event type see ResourceListener.java, allow combination of multiple events. * @param listener the listener to notify. */ - void registerForLifeCycleEvents(Host.Type type, ResourceLifeCycleListener listener); + public void registerResourceEvent(Integer event, ResourceListener listener); + + public void unregisterResourceEvent(ResourceListener listener); } diff --git a/server/src/com/cloud/resource/ResourceManagerImpl.java b/server/src/com/cloud/resource/ResourceManagerImpl.java index fc97b8238af..d5f55911734 100644 --- a/server/src/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/com/cloud/resource/ResourceManagerImpl.java @@ -23,6 +23,7 @@ import java.net.URLDecoder; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import javax.ejb.Local; @@ -118,11 +119,103 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma protected long _nodeId = ManagementServerNode.getManagementServerId(); - protected HashMap _listeners = new HashMap(); + protected HashMap> _lifeCycleListeners = new HashMap>(); + private void insertListener(Integer event, ResourceListener listener) { + List lst = _lifeCycleListeners.get(event); + if (lst == null) { + lst = new ArrayList(); + _lifeCycleListeners.put(event, lst); + } + + if (lst.contains(listener)) { + throw new CloudRuntimeException("Duplicate resource lisener:" + listener.getName()); + } + + lst.add(listener); + } + @Override - public void registerForLifeCycleEvents(Host.Type type, ResourceLifeCycleListener listener) { - _listeners.put(type, listener); + public void registerResourceEvent(Integer event, ResourceListener listener) { + synchronized (_lifeCycleListeners) { + if ((event & ResourceListener.EVENT_DISCOVER_BEFORE) == 1) { + insertListener(ResourceListener.EVENT_DISCOVER_BEFORE, listener); + } + if ((event & ResourceListener.EVENT_DISCOVER_AFTER) == 1) { + insertListener(ResourceListener.EVENT_DISCOVER_AFTER, listener); + } + if ((event & ResourceListener.EVENT_DELETE_HOST_BEFORE) == 1) { + insertListener(ResourceListener.EVENT_DELETE_HOST_BEFORE, listener); + } + if ((event & ResourceListener.EVENT_DELETE_HOST_AFTER) == 1) { + insertListener(ResourceListener.EVENT_DELETE_HOST_AFTER, listener); + } + if ((event & ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE) == 1) { + insertListener(ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE, listener); + } + if ((event & ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER) == 1) { + insertListener(ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER, listener); + } + if ((event & ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE) == 1) { + insertListener(ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE, listener); + } + if ((event & ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER) == 1) { + insertListener(ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER, listener); + } + } + } + + @Override + public void unregisterResourceEvent(ResourceListener listener) { + synchronized (_lifeCycleListeners) { + Iterator it = _lifeCycleListeners.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry> items = (Map.Entry>)it.next(); + List lst = items.getValue(); + lst.remove(listener); + } + } + } + + protected void processResourceEvent(Integer event, Object...params) { + synchronized (_lifeCycleListeners) { + List lst = _lifeCycleListeners.get(event); + if (lst == null || lst.size() == 0) { + return; + } + + String eventName; + for (ResourceListener l : lst) { + if (event == ResourceListener.EVENT_DISCOVER_BEFORE) { + l.processDiscoverEventBefore((Long)params[0], (Long)params[1], (Long)params[2], (URI)params[3], (String)params[4], (String)params[5], (List)params[6]); + eventName = "EVENT_DISCOVER_BEFORE"; + } else if (event == ResourceListener.EVENT_DISCOVER_AFTER) { + l.processDiscoverEventAfter((Map>)params[0]); + eventName = "EVENT_DISCOVER_AFTER"; + } else if (event == ResourceListener.EVENT_DELETE_HOST_BEFORE) { + l.processDeleteHostEventBefore((HostVO)params[0]); + eventName = "EVENT_DELETE_HOST_BEFORE"; + } else if (event == ResourceListener.EVENT_DELETE_HOST_AFTER) { + l.processDeletHostEventAfter((HostVO)params[0]); + eventName = "EVENT_DELETE_HOST_AFTER"; + } else if (event == ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE) { + l.processCancelMaintenaceEventBefore((Long)params[0]); + eventName = "EVENT_CANCEL_MAINTENANCE_BEFORE"; + } else if (event == ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER) { + l.processCancelMaintenaceEventAfter((Long)params[0]); + eventName = "EVENT_CANCEL_MAINTENANCE_AFTER"; + } else if (event == ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE) { + l.processPrepareMaintenaceEventBefore((Long)params[0]); + eventName = "EVENT_PREPARE_MAINTENANCE_BEFORE"; + } else if (event == ResourceListener.EVENT_PREPARE_MAINTENANCE_AFTER) { + l.processPrepareMaintenaceEventAfter((Long)params[0]); + eventName = "EVENT_PREPARE_MAINTENANCE_AFTER"; + } else { + throw new CloudRuntimeException("Unknown resource event:" + event); + } + s_logger.debug("Send resource event " + eventName + " to listener " + l.getName()); + } + } } @Override @@ -479,6 +572,7 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma isHypervisorTypeSupported = true; Map> resources = null; + processResourceEvent(ResourceListener.EVENT_DISCOVER_BEFORE, dcId, podId, clusterId, uri, username, password, hostTags); try { resources = discoverer.find(dcId, podId, clusterId, uri, username, password); } catch(DiscoveryException e) { @@ -486,6 +580,9 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma } catch (Exception e) { s_logger.info("Exception in host discovery process with discoverer: " + discoverer.getName() + ", skip to another discoverer if there is any"); } + processResourceEvent(ResourceListener.EVENT_DISCOVER_AFTER, resources); + + //TODO: move this out using resource listener if (resources != null) { for (Map.Entry> entry : resources.entrySet()) { ServerResource resource = entry.getKey(); @@ -538,12 +635,17 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma throw new InvalidParameterValueException("Host with id " + hostId + " doesn't exist"); } _accountMgr.checkAccessAndSpecifyAuthority(UserContext.current().getCaller(), host.getDataCenterId()); + + processResourceEvent(ResourceListener.EVENT_DELETE_HOST_BEFORE, host); + boolean res = false; if (Host.Type.SecondaryStorage.equals(host.getType())) { _secondaryStorageMgr.deleteHost(hostId); - return true; + res = true; } else { - return _agentMgr.deleteHost(hostId, isForced, forceDestroy, caller); + res = _agentMgr.deleteHost(hostId, isForced, forceDestroy, caller); } + processResourceEvent(ResourceListener.EVENT_DELETE_HOST_AFTER, host); + return res; } @Override @@ -735,7 +837,9 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma throw new InvalidParameterValueException("Host with id " + hostId.toString() + " doesn't exist"); } + processResourceEvent(ResourceListener.EVENT_CANCEL_MAINTENANCE_BEFORE, hostId); boolean success = _agentMgr.cancelMaintenance(hostId); + processResourceEvent(ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER, hostId); if (!success) { throw new CloudRuntimeException("Internal error cancelling maintenance."); } @@ -777,7 +881,9 @@ public class ResourceManagerImpl implements ResourceManager, ResourceService, Ma } try { + processResourceEvent(ResourceListener.EVENT_PREPARE_MAINTENANCE_BEFORE, hostId); if (_agentMgr.maintain(hostId)) { + processResourceEvent(ResourceListener.EVENT_CANCEL_MAINTENANCE_AFTER, hostId); return _hostDao.findById(hostId); } else { throw new CloudRuntimeException("Unable to prepare for maintenance host " + hostId);