diff options
Diffstat (limited to 'qpid/java')
3 files changed, 113 insertions, 39 deletions
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<BDBHAVirtu throw new IllegalStateException("Environment facade is not created"); } + try + { + Set<ReplicationNode> 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<BDBHAVirtu private boolean processIntruderNode(ReplicationNode node) { - String hostAndPort = node.getHostName() + ":" + node.getPort(); + final String hostAndPort = node.getHostName() + ":" + node.getPort(); getEventLogger().message(getGroupLogSubject(), HighAvailabilityMessages.INTRUDER_DETECTED(node.getName(), hostAndPort)); boolean inManagementMode = getParent(Broker.class).isManagementMode(); @@ -1069,35 +1087,16 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu BDBHAVirtualHostNodeImpl.this.getName(), _lastRole.get(), String.valueOf(BDBHAVirtualHostNodeImpl.this.getPermittedNodes()) )); - getTaskExecutor().submit(new Task<Void>() { @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<BDBHAVirtu } } + protected void shutdownOnIntruder(String intruderHostAndPort) + { + LOGGER.info("Intruder detected (" + intruderHostAndPort + "), stopping and setting state to ERRORED"); + + State initialState = getState(); + 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(initialState, State.ERRORED); + } + private abstract class VirtualHostNodeGroupTask implements Task<Void> { @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.<String, Object>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<String, Object> node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber, intruderPortNumber); + BDBHAVirtualHostNode<?> node = _helper.createAndStartHaVHN(node1Attributes); + + Map<String, Object> 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<String> permittedNodes = new ArrayList<String>(); + permittedNodes.add(helperAddress); + node.setAttributes(Collections.<String, Object>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<String, Object> node1Attributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, node1PortNumber, node2PortNumber); - BDBHAVirtualHostNode<?> node1 = _helper.createAndStartHaVHN(node1Attributes); + Map<String, Object> nodeAttributes = _helper.createNodeAttributes(nodeName, groupName, helperAddress, helperAddress, nodeName, nodePortNumber, intruderPortNumber); + BDBHAVirtualHostNode<?> node = _helper.createAndStartHaVHN(nodeAttributes); - Map<String, Object> node2Attributes = _helper.createNodeAttributes("node2", groupName, "localhost:" + node2PortNumber, helperAddress, nodeName); - node2Attributes.put(BDBHAVirtualHostNode.PRIORITY, 0); - BDBHAVirtualHostNode<?> node2 = _helper.createAndStartHaVHN(node2Attributes); + Map<String, Object> 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<String> permittedNodes = new ArrayList<String>(); permittedNodes.add(helperAddress); - node1.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); + node.setAttributes(Collections.<String, Object>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<X extends ConfiguredObject<X>> im if(desiredState == getDesiredState() && desiredState != state) { attainStateIfOpenedOrReopenFailed(); - return getState(); + final State currentState = getState(); + if (currentState != state) + { + notifyStateChanged(state, currentState); + } + return currentState; } else { |
