From 596241e890427e48f78917b9b82aa73816dd2dd6 Mon Sep 17 00:00:00 2001 From: Andrew MacBean Date: Wed, 8 Oct 2014 16:34:10 +0000 Subject: QPID-6134: [Java Broker] Restarting a node that has detected an intruder should go back into the ERROR state not ACTIVE git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1630167 13f79535-47bb-0310-9956-ffa450edef68 --- .../berkeleydb/BDBHAVirtualHostNodeImpl.java | 65 ++++++++++++------ .../store/berkeleydb/BDBHAVirtualHostNodeTest.java | 80 +++++++++++++++++----- .../server/model/AbstractConfiguredObject.java | 7 +- 3 files changed, 113 insertions(+), 39 deletions(-) (limited to 'qpid/java') diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java index 230b478a68..0003e74dbc 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeImpl.java @@ -335,6 +335,24 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode remoteNodes = environmentFacade.getEnvironment().getGroup().getNodes(); + for (ReplicationNode node : remoteNodes) + { + String nodeAddress = node.getHostName() + ":" + node.getPort(); + if (!_permittedNodes.contains(nodeAddress)) + { + shutdownOnIntruder(nodeAddress); + throw new IllegalStateException("Intruder node detected: " + nodeAddress); + } + } + } + catch (DatabaseException dbe) + { + environmentFacade.handleDatabaseException("DB exception while checking for intruder node", dbe); + } + if (_environmentFacade.compareAndSet(null, environmentFacade)) { environmentFacade.setStateChangeListener(new EnvironmentStateChangeListener()); @@ -1047,7 +1065,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode() { @Override public Void execute() { - State state = getState(); - if (state != State.ERRORED) - { - try - { - stopAndSetStateTo(State.ERRORED); - } - catch(Exception e) - { - LOGGER.error("Unexpected exception on closing the node when intruder is detected ", e); - } - finally - { - closeEnvironment(); - - _lastRole.set(NodeRole.DETACHED); - attributeSet(ROLE, _role, NodeRole.DETACHED); - } - notifyStateChanged(state, State.ERRORED); - } + shutdownOnIntruder(hostAndPort); return null; } }); + return false; } } @@ -1119,6 +1118,28 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode { @Override diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java index e23346cd6a..ee990d3211 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/BDBHAVirtualHostNodeTest.java @@ -42,6 +42,7 @@ import com.sleepycat.je.rep.ReplicatedEnvironment; import com.sleepycat.je.rep.ReplicationConfig; import org.apache.qpid.server.configuration.IllegalConfigurationException; +import org.apache.qpid.server.model.AbstractConfiguredObject; import org.apache.qpid.server.model.ConfigurationChangeListener; import org.apache.qpid.server.model.ConfiguredObject; import org.apache.qpid.server.model.RemoteReplicationNode; @@ -489,21 +490,70 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase nonMasterNode.setAttributes(Collections.singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, amendedPermittedNodes)); } + public void testIntruderProtection() throws Exception + { + int nodePortNumber = _portHelper.getNextAvailable(); + int intruderPortNumber = _portHelper.getNextAvailable(); + + String helperAddress = "localhost:" + nodePortNumber; + String groupName = "group"; + String nodeName = "node"; + + Map node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber, intruderPortNumber); + BDBHAVirtualHostNode node = _helper.createAndStartHaVHN(node1Attributes); + + Map intruderAttributes = _helper.createNodeAttributes("intruder", groupName, "localhost:" + intruderPortNumber, helperAddress, nodeName); + intruderAttributes.put(BDBHAVirtualHostNode.PRIORITY, 0); + BDBHAVirtualHostNode intruder = _helper.createAndStartHaVHN(intruderAttributes); + + final CountDownLatch stopLatch = new CountDownLatch(1); + ConfigurationChangeListener listener = new NoopConfigurationChangeListener() + { + @Override + public void stateChanged(ConfiguredObject object, State oldState, State newState) + { + if (newState == State.ERRORED) + { + stopLatch.countDown(); + } + } + }; + node.addChangeListener(listener); + + List permittedNodes = new ArrayList(); + permittedNodes.add(helperAddress); + node.setAttributes(Collections.singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + + assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(10, TimeUnit.SECONDS)); + + // Try top re start the ERRORED node and ensure exception is thrown + try + { + node.start(); + fail("Restart of node should have thrown exception"); + } + catch (IllegalStateException ise) + { + assertEquals("Unexpected exception when restarting node post intruder detection", "Intruder node detected: " + "localhost:" + intruderPortNumber, ise.getMessage()); + } + _helper.awaitForAttributeChange(node, AbstractConfiguredObject.STATE, State.ERRORED); + } + public void testIntruderProtectionInManagementMode() throws Exception { - int node1PortNumber = _portHelper.getNextAvailable(); - int node2PortNumber = _portHelper.getNextAvailable(); + int nodePortNumber = _portHelper.getNextAvailable(); + int intruderPortNumber = _portHelper.getNextAvailable(); - String helperAddress = "localhost:" + node1PortNumber; + String helperAddress = "localhost:" + nodePortNumber; String groupName = "group"; - String nodeName = "node1"; + String nodeName = "node"; - Map node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, node1PortNumber, node2PortNumber); - BDBHAVirtualHostNode node1 = _helper.createAndStartHaVHN(node1Attributes); + Map nodeAttributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber, intruderPortNumber); + BDBHAVirtualHostNode node = _helper.createAndStartHaVHN(nodeAttributes); - Map node2Attributes = _helper.createNodeAttributes("node2", groupName, "localhost:" + node2PortNumber, helperAddress, nodeName); - node2Attributes.put(BDBHAVirtualHostNode.PRIORITY, 0); - BDBHAVirtualHostNode node2 = _helper.createAndStartHaVHN(node2Attributes); + Map intruderAttributes = _helper.createNodeAttributes("intruder", groupName, "localhost:" + intruderPortNumber, helperAddress, nodeName); + intruderAttributes.put(BDBHAVirtualHostNode.PRIORITY, 0); + BDBHAVirtualHostNode intruder = _helper.createAndStartHaVHN(intruderAttributes); final CountDownLatch stopLatch = new CountDownLatch(1); ConfigurationChangeListener listener = new NoopConfigurationChangeListener() @@ -517,21 +567,19 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase } } }; - node1.addChangeListener(listener); + node.addChangeListener(listener); List permittedNodes = new ArrayList(); permittedNodes.add(helperAddress); - node1.setAttributes(Collections.singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + node.setAttributes(Collections.singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(10, TimeUnit.SECONDS)); + // test that if management mode is enabled then the node can start without exception when(_helper.getBroker().isManagementMode()).thenReturn(true); - node1.start(); - - _helper.awaitRemoteNodes(node1, 1); + node.start(); - BDBHARemoteReplicationNode remote = _helper.findRemoteNode(node1, node2.getName()); - remote.delete(); + _helper.awaitForAttributeChange(node, AbstractConfiguredObject.STATE, State.ERRORED); } public void testPermittedNodesChangedOnReplicaNodeOnlyOnceAfterBeingChangedOnMaster() throws Exception diff --git a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java index 1832ec4732..e6f79fef16 100644 --- a/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java +++ b/qpid/java/broker-core/src/main/java/org/apache/qpid/server/model/AbstractConfiguredObject.java @@ -949,7 +949,12 @@ public abstract class AbstractConfiguredObject> im if(desiredState == getDesiredState() && desiredState != state) { attainStateIfOpenedOrReopenFailed(); - return getState(); + final State currentState = getState(); + if (currentState != state) + { + notifyStateChanged(state, currentState); + } + return currentState; } else { -- cgit v1.2.1