changeset 1316:f9acec89f53f

Filter-based VM blacklist This patch adds a blacklist mechanism for VMs in the agent. Users of the OSGi service can add Filters to the blacklist, where matching VmRefs will not be monitored by Thermostat. In addition to adding the VmBlacklist service, since the blacklist uses VmRef Filters, this patch modifies SystemBackend and friends in order to assemble the VmRef required by the blacklist. This blacklist a necessary feature for the Agent Proxy in subsequent patches. The Agent spawns a short-lived helper Java process for each VM, called an Agent Proxy. If these Proxies are not blacklisted, they too will be monitored causing another Agent Proxy to be spawned. This would continue forever, spawning an infinite amount of Proxies. The Agent Proxy mechanism uses the blacklist by matching the Agent Proxy's main class name against the VmRef in the Filter. This relies on VmRef.getName() returning the main class name, as it currently does. There are a couple of other fixes to SystemBackend I noticed while working on this patch, which came about by having short living Java processes around. In sendNewVM, I have removed the try/catch block. The effect of this is that if we fail to extract information about the VM from jvmstat, we don't continue to monitor that JVM or notify other Backends about it. This happens occasionally with the Agent Proxy, because it is such a short-lived process, that it dies while we are trying to gather info about it for the first time. Likewise in sendStoppedVM, we now check if monitoredVms contains the PID before proceeding to avoid a possible NPE. Reviewed-by: neugens, jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-November/008702.html PR1460
author Elliott Baron <ebaron@redhat.com>
date Thu, 14 Nov 2013 11:28:44 -0500
parents 0a4e551bef62
children b8b5934f7977
files agent/core/src/main/java/com/redhat/thermostat/agent/VmBlacklist.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/VmBlacklistImpl.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java system-backend/src/test/java/com/redhat/thermostat/backend/system/JvmStatHostListenerTest.java system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java
diffstat 9 files changed, 237 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/VmBlacklist.java	Thu Nov 14 11:28:44 2013 -0500
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.agent;
+
+import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.storage.core.VmRef;
+
+/**
+ * Maintains a list of JVM processes that Thermostat should not
+ * monitor.
+ */
+public interface VmBlacklist {
+    
+    /**
+     * Adds a {@link Filter} to the blacklist. Virtual machines that
+     * match the filter will not be monitored.
+     * @param filter - a filter whose matching VMs should not be monitored
+     */
+    void addVmFilter(Filter<VmRef> filter);
+    
+    /**
+     * Removes a {@link Filter} from the blacklist. New virtual machines
+     * will no longer be tested against this filter for blacklisting.
+     * @param filter - a filter previously in the blacklist
+     */
+    void removeVmFilter(Filter<VmRef> filter);
+    
+    /**
+     * Returns whether the given virtual machine should be monitored
+     * by matching it against filters in the blacklist. If any filter
+     * matches, then this method will return true.
+     * @param ref - a reference to the virtual machine to be tested
+     *              against the blacklist
+     * @return true if blacklisted, false otherwise
+     */
+    boolean isBlacklisted(VmRef ref);
+
+}
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Thu Nov 14 11:28:44 2013 -0500
@@ -39,6 +39,7 @@
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
 import com.redhat.thermostat.utils.username.UserNameUtil;
@@ -50,6 +51,7 @@
     public void start(BundleContext context) throws Exception {
         context.registerService(MXBeanConnectionPool.class, new MXBeanConnectionPoolImpl(), null);
         context.registerService(UserNameUtil.class, new UserNameUtilImpl(), null);
+        context.registerService(VmBlacklist.class, new VmBlacklistImpl(), null);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/VmBlacklistImpl.java	Thu Nov 14 11:28:44 2013 -0500
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012, 2013 Red Hat, Inc.
+ *
+ * This file is part of Thermostat.
+ *
+ * Thermostat 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, or (at your
+ * option) any later version.
+ *
+ * Thermostat 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 Thermostat; see the file COPYING.  If not see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * Linking this code with other modules is making a combined work
+ * based on this code.  Thus, the terms and conditions of the GNU
+ * General Public License cover the whole combination.
+ *
+ * As a special exception, the copyright holders of this code give
+ * you permission to link this code with independent modules to
+ * produce an executable, regardless of the license terms of these
+ * independent modules, and to copy and distribute the resulting
+ * executable under terms of your choice, provided that you also
+ * meet, for each linked independent module, the terms and conditions
+ * of the license of that module.  An independent module is a module
+ * which is not derived from or based on this code.  If you modify
+ * this code, you may extend this exception to your version of the
+ * library, but you are not obligated to do so.  If you do not wish
+ * to do so, delete this exception statement from your version.
+ */
+
+package com.redhat.thermostat.agent.internal;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import com.redhat.thermostat.agent.VmBlacklist;
+import com.redhat.thermostat.common.Filter;
+import com.redhat.thermostat.storage.core.VmRef;
+
+public class VmBlacklistImpl implements VmBlacklist {
+    
+    private final List<Filter<VmRef>> filters;
+    
+    public VmBlacklistImpl() {
+        this.filters = new CopyOnWriteArrayList<>();
+    }
+
+    @Override
+    public void addVmFilter(Filter<VmRef> filter) {
+        filters.add(filter);
+    }
+
+    @Override
+    public void removeVmFilter(Filter<VmRef> filter) {
+        filters.remove(filter);
+    }
+
+    @Override
+    public boolean isBlacklisted(VmRef ref) {
+        boolean result = false;
+        for (Filter<VmRef> filter : filters) {
+            if (filter.matches(ref)) {
+                result = true;
+            }
+        }
+        return result;
+    }
+
+}
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Thu Nov 14 11:28:44 2013 -0500
@@ -40,6 +40,7 @@
 
 import org.junit.Test;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.testutils.StubBundleContext;
 import com.redhat.thermostat.utils.management.MXBeanConnectionPool;
 import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl;
@@ -58,5 +59,6 @@
 
         assertTrue(context.isServiceRegistered(MXBeanConnectionPool.class.getName(), MXBeanConnectionPoolImpl.class));
         assertTrue(context.isServiceRegistered(UserNameUtil.class.getName(), UserNameUtilImpl.class));
+        assertTrue(context.isServiceRegistered(VmBlacklist.class.getName(), VmBlacklistImpl.class));
     }
 }
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/JvmStatHostListener.java	Thu Nov 14 11:28:44 2013 -0500
@@ -52,10 +52,13 @@
 import sun.jvmstat.monitor.event.HostListener;
 import sun.jvmstat.monitor.event.VmStatusChangeEvent;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.agent.VmStatusListener.Status;
 import com.redhat.thermostat.backend.system.ProcessUserInfoBuilder.ProcessUserInfo;
 import com.redhat.thermostat.common.Pair;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
@@ -70,12 +73,18 @@
     private final ProcessUserInfoBuilder userInfoBuilder;
     private final WriterID writerId;
     private Map<Integer, Pair<String, MonitoredVm>> monitoredVms  = new HashMap<>();
+    private final HostRef hostRef;
+    private final VmBlacklist blacklist;
 
-    JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier, ProcessUserInfoBuilder userInfoBuilder, WriterID writerId) {
+    JvmStatHostListener(VmInfoDAO vmInfoDAO, VmStatusChangeNotifier notifier, 
+            ProcessUserInfoBuilder userInfoBuilder, WriterID writerId, HostRef hostRef,
+            VmBlacklist blacklist) {
         this.vmInfoDAO = vmInfoDAO;
         this.notifier = notifier;
         this.userInfoBuilder = userInfoBuilder;
         this.writerId = writerId;
+        this.hostRef = hostRef;
+        this.blacklist = blacklist;
     }
 
     @Override
@@ -93,9 +102,9 @@
                 logger.fine("New vm: " + newVm);
                 sendNewVM(newVm, host);
             } catch (MonitorException e) {
-                logger.log(Level.WARNING, "error getting info for new vm" + newVm, e);
+                logger.log(Level.WARNING, "error getting info for new vm " + newVm, e);
             } catch (URISyntaxException e) {
-                logger.log(Level.WARNING, "error getting info for new vm" + newVm, e);
+                logger.log(Level.WARNING, "error getting info for new vm " + newVm, e);
             }
         }
 
@@ -104,36 +113,44 @@
                 logger.fine("stopped vm: " + stoppedVm);
                 sendStoppedVM(stoppedVm, host);
             } catch (URISyntaxException e) {
-                logger.log(Level.WARNING, "error getting info for stopped vm" + stoppedVm, e);
+                logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e);
             } catch (MonitorException e) {
-                logger.log(Level.WARNING, "error getting info for stopped vm" + stoppedVm, e);
+                logger.log(Level.WARNING, "error getting info for stopped vm " + stoppedVm, e);
             }
         }
     }
 
     private void sendNewVM(Integer vmPid, MonitoredHost host)
             throws MonitorException, URISyntaxException {
+        // Propagate any MonitorException, and do not notify Backends or remember
+        // VMs when we fail to extract the necessary information.
+        // http://icedtea.classpath.org/pipermail/thermostat/2013-November/008702.html
         MonitoredVm vm = host.getMonitoredVm(host.getHostIdentifier().resolve(
                 new VmIdentifier(vmPid.toString())));
         if (vm != null) {
             JvmStatDataExtractor extractor = new JvmStatDataExtractor(vm);
             String vmId = UUID.randomUUID().toString();
-            try {
-                long startTime = System.currentTimeMillis();
-                long stopTime = Long.MIN_VALUE;
-                recordVmInfo(vmId, vmPid, startTime, stopTime, extractor);
+            long startTime = System.currentTimeMillis();
+            long stopTime = Long.MIN_VALUE;
+            VmInfo info = createVmInfo(vmId, vmPid, startTime, stopTime, extractor);
+
+            // Check blacklist
+            VmRef vmRef = new VmRef(hostRef, vmId, vmPid, info.getMainClass());
+            if (!blacklist.isBlacklisted(vmRef)) {
+                vmInfoDAO.putVmInfo(info);
+
+                notifier.notifyVmStatusChange(Status.VM_STARTED, vmId, vmPid);
                 logger.finer("Sent VM_STARTED messsage");
-            } catch (MonitorException me) {
-                logger.log(Level.WARNING, "error getting vm info for " + vmId, me);
+
+                monitoredVms.put(vmPid, new Pair<>(vmId, vm));
             }
-
-            notifier.notifyVmStatusChange(Status.VM_STARTED, vmId, vmPid);
-
-            monitoredVms.put(vmPid, new Pair<>(vmId, vm));
+            else {
+                logger.info("Skipping VM: " + vmPid);
+            }
         }
     }
 
-    void recordVmInfo(String vmId, Integer vmPid, long startTime, long stopTime,
+    VmInfo createVmInfo(String vmId, Integer vmPid, long startTime, long stopTime,
             JvmStatDataExtractor extractor) throws MonitorException {
         Map<String, String> properties = new HashMap<String, String>();
         ProcDataSource dataSource = new ProcDataSource();
@@ -146,13 +163,13 @@
                 extractor.getMainClass(), extractor.getCommandLine(),
                 extractor.getVmName(), extractor.getVmInfo(), extractor.getVmVersion(), extractor.getVmArguments(),
                 properties, environment, loadedNativeLibraries, userInfo.getUid(), userInfo.getUsername());
-        vmInfoDAO.putVmInfo(info);
+        return info;
     }
 
     private void sendStoppedVM(Integer vmPid, MonitoredHost host) throws URISyntaxException, MonitorException {
         
         VmIdentifier resolvedVmID = host.getHostIdentifier().resolve(new VmIdentifier(vmPid.toString()));
-        if (resolvedVmID != null) {
+        if (resolvedVmID != null && monitoredVms.containsKey(vmPid)) {
             Pair<String, MonitoredVm> vmData = monitoredVms.remove(vmPid);
             
             String vmId = vmData.getFirst();
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/SystemBackend.java	Thu Nov 14 11:28:44 2013 -0500
@@ -42,19 +42,20 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
-import org.osgi.framework.BundleContext;
-
 import sun.jvmstat.monitor.HostIdentifier;
 import sun.jvmstat.monitor.MonitorException;
 import sun.jvmstat.monitor.MonitoredHost;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.backend.BaseBackend;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.common.utils.LoggingUtils;
+import com.redhat.thermostat.storage.core.HostRef;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
 import com.redhat.thermostat.storage.dao.NetworkInterfaceInfoDAO;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
+import com.redhat.thermostat.storage.model.HostInfo;
 import com.redhat.thermostat.storage.model.NetworkInterfaceInfo;
 import com.redhat.thermostat.utils.ProcDataSource;
 import com.redhat.thermostat.utils.username.UserNameUtil;
@@ -65,6 +66,7 @@
 
     private HostInfoDAO hostInfos;
     private NetworkInterfaceInfoDAO networkInterfaces;
+    private VmInfoDAO vmInfoDAO;
 
     private long procCheckInterval = 1000; // TODO make this configurable.
 
@@ -76,21 +78,29 @@
 
     private final NetworkInfoBuilder networkInfoBuilder;
     private final HostInfoBuilder hostInfoBuilder;
-
+    private final ProcessUserInfoBuilder userInfoBuilder;
+    private final VmStatusChangeNotifier notifier;
+    private final WriterID writerId;
+    private final VmBlacklist blacklist;
 
     public SystemBackend(HostInfoDAO hostInfoDAO, NetworkInterfaceInfoDAO netInfoDAO, VmInfoDAO vmInfoDAO,
-            Version version, VmStatusChangeNotifier notifier, UserNameUtil userNameUtil, WriterID writerId) {
+            Version version, VmStatusChangeNotifier notifier, UserNameUtil userNameUtil, WriterID writerId,
+            VmBlacklist blacklist) {
         super("System Backend",
                 "Gathers basic information from the system",
                 "Red Hat, Inc.",
                 version.getVersionNumber(), true);
         this.hostInfos = hostInfoDAO;
         this.networkInterfaces = netInfoDAO;
+        this.vmInfoDAO = vmInfoDAO;
+        this.notifier = notifier;
+        this.writerId = writerId;
+        this.blacklist = blacklist;
 
         ProcDataSource source = new ProcDataSource();
         hostInfoBuilder = new HostInfoBuilder(source, writerId);
-        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, new ProcessUserInfoBuilder(source, userNameUtil), writerId);
         networkInfoBuilder = new NetworkInfoBuilder(writerId);
+        userInfoBuilder = new ProcessUserInfoBuilder(source, userNameUtil);
     }
 
     @Override
@@ -102,7 +112,8 @@
         if (!getObserveNewJvm()) {
             logger.fine("not monitoring new vms");
         }
-        hostInfos.putHostInfo(hostInfoBuilder.build());
+        HostInfo hostInfo = hostInfoBuilder.build();
+        hostInfos.putHostInfo(hostInfo);
 
         timer = new Timer();
         timer.scheduleAtFixedRate(new TimerTask() {
@@ -116,6 +127,9 @@
 
         try {
             hostId = new HostIdentifier((String) null);
+            HostRef hostRef = new HostRef(hostInfo.getAgentId(), hostInfo.getHostname());
+            hostListener = new JvmStatHostListener(vmInfoDAO, notifier, 
+                    userInfoBuilder, writerId, hostRef, blacklist);
             host = MonitoredHost.getMonitoredHost(hostId);
             host.addHostListener(hostListener);
         } catch (MonitorException me) {
--- a/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/system-backend/src/main/java/com/redhat/thermostat/backend/system/osgi/SystemBackendActivator.java	Thu Nov 14 11:28:44 2013 -0500
@@ -42,6 +42,7 @@
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceRegistration;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.backend.Backend;
 import com.redhat.thermostat.backend.BackendService;
 import com.redhat.thermostat.backend.system.SystemBackend;
@@ -75,7 +76,8 @@
                 NetworkInterfaceInfoDAO.class,
                 VmInfoDAO.class,
                 UserNameUtil.class,
-                WriterID.class // system backend uses it
+                WriterID.class, // system backend uses it
+                VmBlacklist.class,
         };
         tracker = new MultipleServiceTracker(context, deps, new Action() {
             @Override
@@ -87,7 +89,9 @@
                 UserNameUtil userNameUtil = (UserNameUtil) services.get(UserNameUtil.class.getName());
                 Version version = new Version(context.getBundle());
                 WriterID id = (WriterID) services.get(WriterID.class.getName());
-                backend = new SystemBackend(hostInfoDAO, netInfoDAO, vmInfoDAO, version, notifier, userNameUtil, id);
+                VmBlacklist blacklist = (VmBlacklist) services.get(VmBlacklist.class.getName());
+                backend = new SystemBackend(hostInfoDAO, netInfoDAO, vmInfoDAO, version, notifier, 
+                        userNameUtil, id, blacklist);
                 reg = context.registerService(Backend.class, backend, null);
             }
             
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/JvmStatHostListenerTest.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/JvmStatHostListenerTest.java	Thu Nov 14 11:28:44 2013 -0500
@@ -68,8 +68,11 @@
 import sun.jvmstat.monitor.VmIdentifier;
 import sun.jvmstat.monitor.event.VmStatusChangeEvent;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.agent.VmStatusListener.Status;
 import com.redhat.thermostat.backend.system.ProcessUserInfoBuilder.ProcessUserInfo;
+import com.redhat.thermostat.storage.core.HostRef;
+import com.redhat.thermostat.storage.core.VmRef;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.VmInfoDAO;
 import com.redhat.thermostat.storage.model.VmInfo;
@@ -94,6 +97,7 @@
     private JvmStatDataExtractor extractor;
     private VmInfoDAO vmInfoDAO;
     private VmStatusChangeNotifier notifier;
+    private VmBlacklist blacklist;
 
     @Before
     public void setup() throws MonitorException, URISyntaxException {
@@ -105,7 +109,9 @@
         when(userInfoBuilder.build(any(int.class))).thenReturn(userInfo);
 
         WriterID id = mock(WriterID.class);
-        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id);
+        HostRef hostRef = mock(HostRef.class);
+        blacklist = mock(VmBlacklist.class);
+        hostListener = new JvmStatHostListener(vmInfoDAO, notifier, userInfoBuilder, id, hostRef, blacklist);
         
         host = mock(MonitoredHost.class);
         HostIdentifier hostId = mock(HostIdentifier.class);
@@ -155,6 +161,19 @@
     }
     
     @Test
+    public void testNewVMBlackListed() throws InterruptedException, MonitorException {
+        when(blacklist.isBlacklisted(any(VmRef.class))).thenReturn(true).thenReturn(false);
+        startVMs();
+        
+        assertFalse(hostListener.getMonitoredVms().containsKey(1));
+        assertTrue(hostListener.getMonitoredVms().containsKey(2));
+        assertEquals(monitoredVm2, hostListener.getMonitoredVms().get(2).getSecond());
+        
+        UUID uuid = UUID.fromString(hostListener.getMonitoredVms().get(2).getFirst());
+        verify(notifier).notifyVmStatusChange(eq(Status.VM_STARTED), eq(uuid.toString()), (isA(Integer.class)));
+    }
+    
+    @Test
     public void testStoppedVM() throws InterruptedException, MonitorException {
         final Set<Integer> stopped = new HashSet<>();
         stopped.add(1);
@@ -227,20 +246,15 @@
         when(event.getStarted()).thenReturn(started);
         when(event.getTerminated()).thenReturn(Collections.emptySet());
         hostListener.vmStatusChanged(event);
-
-        verify(notifier, times(2)).notifyVmStatusChange(eq(Status.VM_STARTED), anyString(), isA(Integer.class));
     }
 
     @Test
-    public void testRecordVmInfo() throws MonitorException {
+    public void testCreateVmInfo() throws MonitorException {
         final String INFO_ID = "vmId";
         final int INFO_PID = 1;
         final long INFO_STARTTIME = Long.MIN_VALUE;
         final long INFO_STOPTIME = Long.MAX_VALUE;
-        hostListener.recordVmInfo(INFO_ID, INFO_PID, INFO_STARTTIME, INFO_STOPTIME, extractor);
-        ArgumentCaptor<VmInfo> captor = ArgumentCaptor.forClass(VmInfo.class);
-        verify(vmInfoDAO).putVmInfo(captor.capture());
-        VmInfo info = captor.getValue();
+        VmInfo info = hostListener.createVmInfo(INFO_ID, INFO_PID, INFO_STARTTIME, INFO_STOPTIME, extractor);
         
         assertEquals(INFO_PID, info.getVmPid());
         assertEquals(INFO_STARTTIME, info.getStartTimeStamp());
--- a/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Mon Nov 11 11:06:04 2013 +0100
+++ b/system-backend/src/test/java/com/redhat/thermostat/backend/system/SystemBackendTest.java	Thu Nov 14 11:28:44 2013 -0500
@@ -45,6 +45,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import com.redhat.thermostat.agent.VmBlacklist;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.storage.core.WriterID;
 import com.redhat.thermostat.storage.dao.HostInfoDAO;
@@ -70,7 +71,8 @@
         UserNameUtil util = mock(UserNameUtil.class);
 
         WriterID id = mock(WriterID.class);
-        b = new SystemBackend(hDAO, nDAO, vmInfoDAO, version, notifier, util, id);
+        VmBlacklist blacklist = mock(VmBlacklist.class);
+        b = new SystemBackend(hDAO, nDAO, vmInfoDAO, version, notifier, util, id, blacklist);
     }
 
     @Test