diff options
author | Alex Rudyy <orudyy@apache.org> | 2014-08-28 11:07:35 +0000 |
---|---|---|
committer | Alex Rudyy <orudyy@apache.org> | 2014-08-28 11:07:35 +0000 |
commit | 47d244161446d54a68d345f710971f8aa7f1d983 (patch) | |
tree | 0405f2c9523a7d883d94adc195c52d68c232752f | |
parent | 6b522a6b05a7fed3c521ef5b3f59415ca35e3fad (diff) | |
download | qpid-python-47d244161446d54a68d345f710971f8aa7f1d983.tar.gz |
QPID-6048: Move permitted nodes attribute into BDB HA VH in order to be able to identify the intruder node on node start-up
svn merge -c 1620882 https://svn.apache.org/repos/asf/qpid/trunk
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/0.30@1621116 13f79535-47bb-0310-9956-ffa450edef68
24 files changed, 423 insertions, 362 deletions
diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java index 4f47e0fa53..fa916a1316 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacade.java @@ -1220,7 +1220,7 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } } - public static void connectToHelperNodeAndCheckPermittedHosts(String nodeName, String hostPort, String groupName, String helperNodeName, String helperHostPort) + public static Collection<String> connectToHelperNodeAndCheckPermittedHosts(String nodeName, String hostPort, String groupName, String helperNodeName, String helperHostPort) { if (LOGGER.isDebugEnabled()) { @@ -1264,26 +1264,8 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan { throw new IllegalConfigurationException(String.format("Node from '%s' is not permitted!", hostPort)); } - } - private void findMasterNodeStateAndApplyPermittedNodes(Collection<NodeState> nodeStates) - { - if (ReplicatedEnvironment.State.MASTER != _environment.getState()) - { - for (NodeState nodeState : nodeStates) - { - if (nodeState.getNodeState() == ReplicatedEnvironment.State.MASTER) - { - byte[] applicationState = nodeState.getAppState(); - Set<String> permittedNodes = convertApplicationStateBytesToPermittedNodeList(applicationState); - if (!_permittedNodes.equals(permittedNodes)) - { - setPermittedNodes(permittedNodes); - } - break; - } - } - } + return permittedNodes; } private void registerAppStateMonitorIfPermittedNodesSpecified() @@ -1312,16 +1294,17 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } - private void onIntruder(ReplicationGroupListener replicationGroupListener, ReplicationNode replicationNode) + private boolean onIntruder(ReplicationGroupListener replicationGroupListener, ReplicationNode replicationNode) { if (replicationGroupListener != null) { - replicationGroupListener.onIntruderNode(replicationNode); + return replicationGroupListener.onIntruderNode(replicationNode); } else { LOGGER.warn(String.format("Found an intruder node '%s' from ''%s' . The node is not listed in permitted list: %s", replicationNode.getName(), getHostPort(replicationNode), String.valueOf(_permittedNodes))); + return true; } } @@ -1373,46 +1356,55 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan @Override public Void call() { + boolean continueMonitoring = true; try { if (_state.get() == State.OPEN) { try { - detectGroupChangesAndNotify(); + continueMonitoring = detectGroupChangesAndNotify(); } catch(DatabaseException e) { handleDatabaseException("Exception on replication group check", e); } - Map<ReplicationNode, NodeState> nodeStates = discoverNodeStates(_remoteReplicationNodes.values()); - - executeDatabasePingerOnNodeChangesIfMaster(nodeStates); + if (continueMonitoring) + { + Map<ReplicationNode, NodeState> nodeStates = discoverNodeStates(_remoteReplicationNodes.values()); - notifyGroupListenerAboutNodeStates(nodeStates); + executeDatabasePingerOnNodeChangesIfMaster(nodeStates); - findMasterNodeStateAndApplyPermittedNodes(nodeStates.values()); + notifyGroupListenerAboutNodeStates(nodeStates); + } } } finally { State state = _state.get(); - if (state != State.CLOSED && state != State.CLOSING) + if (state != State.CLOSED && state != State.CLOSING && continueMonitoring) { _groupChangeExecutor.schedule(this, REMOTE_NODE_MONITOR_INTERVAL, TimeUnit.MILLISECONDS); } + else + { + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("Monitoring task is not scheduled: state " + state + ", continue monitoring flag " + continueMonitoring); + } + } } return null; } - private void detectGroupChangesAndNotify() + private boolean detectGroupChangesAndNotify() { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Checking for changes in the group " + _configuration.getGroupName() + " on node " + _configuration.getName()); } - + boolean shouldContinue = true; String groupName = _configuration.getGroupName(); ReplicatedEnvironment env = _environment; ReplicationGroupListener replicationGroupListener = _replicationGroupListener.get(); @@ -1446,7 +1438,10 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } else { - onIntruder(replicationGroupListener, replicationNode); + if (!onIntruder(replicationGroupListener, replicationNode)) + { + shouldContinue = false; + } } } else @@ -1473,6 +1468,7 @@ public class ReplicatedEnvironmentFacade implements EnvironmentFacade, StateChan } } } + return shouldContinue; } private Map<ReplicationNode, NodeState> discoverNodeStates(Collection<ReplicationNode> electableNodes) diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicationGroupListener.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicationGroupListener.java index 7367f5cda7..cf6050c3cd 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicationGroupListener.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicationGroupListener.java @@ -51,7 +51,7 @@ public interface ReplicationGroupListener /** * Invoked on intruder node detected */ - void onIntruderNode(ReplicationNode node); + boolean onIntruderNode(ReplicationNode node); void onNoMajority(); diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHost.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHost.java index e2503a8b51..04ac1cf49d 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHost.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHost.java @@ -36,7 +36,6 @@ public interface BDBHAVirtualHost<X extends BDBHAVirtualHost<X>> extends Virtual String COALESCING_SYNC = "coalescingSync"; String DURABILITY = "durability"; String STORE_PATH = "storePath"; - String PERMITTED_NODES = "permittedNodes"; @ManagedAttribute( defaultValue = "SYNC") String getLocalTransactionSynchronizationPolicy(); @@ -55,7 +54,4 @@ public interface BDBHAVirtualHost<X extends BDBHAVirtualHost<X>> extends Virtual @ManagedAttribute(mandatory = true, defaultValue = "0") Long getStoreOverfullSize(); - - @ManagedAttribute(mandatory = true) - List<String> getPermittedNodes(); } diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHostImpl.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHostImpl.java index a005bca194..21cee14fa7 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHostImpl.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhost/berkeleydb/BDBHAVirtualHostImpl.java @@ -20,7 +20,6 @@ */ package org.apache.qpid.server.virtualhost.berkeleydb; -import java.util.List; import java.util.Map; import java.util.Set; @@ -55,9 +54,6 @@ public class BDBHAVirtualHostImpl extends AbstractVirtualHost<BDBHAVirtualHostIm @ManagedAttributeField private Long _storeOverfullSize; - @ManagedAttributeField(afterSet = "applyPermittedNodes") - private List<String> _permittedNodes; - @ManagedObjectFactoryConstructor public BDBHAVirtualHostImpl(final Map<String, Object> attributes, VirtualHostNode<?> virtualHostNode) { @@ -132,34 +128,6 @@ public class BDBHAVirtualHostImpl extends AbstractVirtualHost<BDBHAVirtualHostIm validateTransactionSynchronizationPolicy(policy); } - if(changedAttributes.contains(PERMITTED_NODES)) - { - validatePermittedNodes(((BDBHAVirtualHost<?>)proxyForValidation).getPermittedNodes()); - } - } - - private void validatePermittedNodes(List<String> permittedNodes) - { - if (permittedNodes == null || permittedNodes.isEmpty()) - { - throw new IllegalArgumentException(String.format("Attribute '%s' is mandatory and must be set", PERMITTED_NODES)); - } - for (String permittedNode: permittedNodes) - { - String[] tokens = permittedNode.split(":"); - if (tokens.length != 2) - { - throw new IllegalArgumentException(String.format("Invalid permitted node specified '%s'. ", permittedNode)); - } - try - { - Integer.parseInt(tokens[1]); - } - catch(Exception e) - { - throw new IllegalArgumentException(String.format("Invalid port is specified in permitted node '%s'. ", permittedNode)); - } - } } private void validateTransactionSynchronizationPolicy(String policy) @@ -192,27 +160,12 @@ public class BDBHAVirtualHostImpl extends AbstractVirtualHost<BDBHAVirtualHostIm } @Override - public List<String> getPermittedNodes() - { - return _permittedNodes; - } - - @Override public void onValidate() { super.onValidate(); - validatePermittedNodes(this.getPermittedNodes()); validateTransactionSynchronizationPolicy(this.getLocalTransactionSynchronizationPolicy()); validateTransactionSynchronizationPolicy(this.getRemoteTransactionSynchronizationPolicy()); } - protected void applyPermittedNodes() - { - ReplicatedEnvironmentFacade facade = getReplicatedEnvironmentFacade(); - if (facade != null) - { - facade.setPermittedNodes(getPermittedNodes()); - } - } } diff --git a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNode.java b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNode.java index b76e4d8d5c..252b00d44f 100644 --- a/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNode.java +++ b/qpid/java/bdbstore/src/main/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNode.java @@ -20,10 +20,13 @@ */ package org.apache.qpid.server.virtualhostnode.berkeleydb; +import java.util.List; + import org.apache.qpid.server.model.DerivedAttribute; import org.apache.qpid.server.model.ManagedAttribute; import org.apache.qpid.server.store.berkeleydb.HASettings; + public interface BDBHAVirtualHostNode<X extends BDBHAVirtualHostNode<X>> extends BDBVirtualHostNode<X>, HASettings { public static final String GROUP_NAME = "groupName"; @@ -37,6 +40,7 @@ public interface BDBHAVirtualHostNode<X extends BDBHAVirtualHostNode<X>> extends public static final String LAST_KNOWN_REPLICATION_TRANSACTION_ID = "lastKnownReplicationTransactionId"; public static final String JOIN_TIME = "joinTime"; public static final String HELPER_NODE_NAME = "helperNodeName"; + public static final String PERMITTED_NODES = "permittedNodes"; @ManagedAttribute(mandatory=true) String getGroupName(); @@ -67,4 +71,7 @@ public interface BDBHAVirtualHostNode<X extends BDBHAVirtualHostNode<X>> extends @ManagedAttribute(persist = false) String getHelperNodeName(); + + @ManagedAttribute(persist = true) + List<String> getPermittedNodes(); } 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 06e97afd98..45b865a7a5 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 @@ -23,10 +23,12 @@ package org.apache.qpid.server.virtualhostnode.berkeleydb; import java.net.InetSocketAddress; import java.security.PrivilegedAction; import java.text.MessageFormat; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -126,6 +128,9 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu @ManagedAttributeField private String _helperNodeName; + @ManagedAttributeField(afterSet = "postSetPermittedNodes") + private List<String> _permittedNodes; + @ManagedObjectFactoryConstructor public BDBHAVirtualHostNodeImpl(Map<String, Object> attributes, Broker<?> broker) { @@ -136,6 +141,8 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu protected void validateChange(final ConfiguredObject<?> proxyForValidation, final Set<String> changedAttributes) { super.validateChange(proxyForValidation, changedAttributes); + BDBHAVirtualHostNode<?> proposed = (BDBHAVirtualHostNode<?>)proxyForValidation; + if (changedAttributes.contains(ROLE)) { String currentRole = getRole(); @@ -143,12 +150,17 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu { throw new IllegalStateException("Cannot transfer mastership when not a replica, current role is " + currentRole); } - BDBHAVirtualHostNode<?> proposed = (BDBHAVirtualHostNode<?>)proxyForValidation; + if (!ReplicatedEnvironment.State.MASTER.name().equals(proposed.getRole())) { throw new IllegalArgumentException("Changing role to other value then " + ReplicatedEnvironment.State.MASTER.name() + " is unsupported"); } } + + if (changedAttributes.contains(PERMITTED_NODES)) + { + validatePermittedNodes(proposed.getPermittedNodes()); + } } @Override @@ -227,6 +239,12 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu return _helperNodeName; } + @Override + public List<String> getPermittedNodes() + { + return _permittedNodes; + } + @SuppressWarnings("rawtypes") @Override public Collection<? extends RemoteReplicationNode> getRemoteReplicationNodes() @@ -268,7 +286,8 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu { try { - ReplicatedEnvironmentFacade.connectToHelperNodeAndCheckPermittedHosts(getName(), getAddress(), getGroupName(), getHelperNodeName(), getHelperAddress()); + Collection<String> permittedNodes = ReplicatedEnvironmentFacade.connectToHelperNodeAndCheckPermittedHosts(getName(), getAddress(), getGroupName(), getHelperNodeName(), getHelperAddress()); + setAttribute(PERMITTED_NODES, null, new ArrayList<String>(permittedNodes)); } catch(IllegalConfigurationException e) { @@ -314,6 +333,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu { environmentFacade.setStateChangeListener(new EnvironmentStateChangeListener()); environmentFacade.setReplicationGroupListener(new RemoteNodesDiscoverer()); + environmentFacade.setPermittedNodes(_permittedNodes); } } @@ -416,6 +436,14 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu _virtualHostNodePrincipalName = MessageFormat.format(VIRTUAL_HOST_PRINCIPAL_NAME_FORMAT, getGroupName(), getName()); } + @Override + public void onOpen() + { + super.onOpen(); + + validatePermittedNodes(_permittedNodes); + } + private void onMaster() { try @@ -719,6 +747,40 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu hostAttributes, vhostRecord.getParents()); } + protected void postSetPermittedNodes() + { + ReplicatedEnvironmentFacade replicatedEnvironmentFacade = getReplicatedEnvironmentFacade(); + if (replicatedEnvironmentFacade != null) + { + replicatedEnvironmentFacade.setPermittedNodes(_permittedNodes); + } + } + + private void validatePermittedNodes(List<String> permittedNodes) + { + if (permittedNodes == null || permittedNodes.isEmpty()) + { + throw new IllegalArgumentException(String.format("Attribute '%s' is mandatory and must be set", PERMITTED_NODES)); + } + for (String permittedNode: permittedNodes) + { + String[] tokens = permittedNode.split(":"); + if (tokens.length != 2) + { + throw new IllegalArgumentException(String.format("Invalid permitted node specified '%s'. ", permittedNode)); + } + try + { + Integer.parseInt(tokens[1]); + } + catch(Exception e) + { + throw new IllegalArgumentException(String.format("Invalid port is specified in permitted node '%s'. ", permittedNode)); + } + } + + } + private class RemoteNodesDiscoverer implements ReplicationGroupListener { @Override @@ -827,6 +889,23 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu getEventLogger().message(getGroupLogSubject(), HighAvailabilityMessages.JOINED(remoteNode.getName(), remoteNode.getAddress())); remoteNode.setDetached(false); } + if (ReplicatedEnvironment.State.MASTER.name().equals(remoteNode.getRole())) + { + byte[] applicationState = nodeState.getAppState(); + Set<String> permittedNodes = ReplicatedEnvironmentFacade.convertApplicationStateBytesToPermittedNodeList(applicationState); + if (!_permittedNodes.equals(permittedNodes)) + { + if (_permittedNodes.contains(remoteNode.getAddress())) + { + setAttribute(PERMITTED_NODES, _permittedNodes, new ArrayList<String>(permittedNodes)); + } + else + { + LOGGER.warn("Cannot change permitted nodes from Master as existing master node '" + remoteNode.getName() + + "' (" + remoteNode.getAddress() + ") is not in list of trusted nodes " + _permittedNodes); + } + } + } } String newRole = remoteNode.getRole(); @@ -838,20 +917,20 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu } @Override - public void onIntruderNode(final ReplicationNode node) + public boolean onIntruderNode(final ReplicationNode node) { - Subject.doAs(SecurityManager.getSystemTaskSubject(_virtualHostNodePrincipalName), new PrivilegedAction<Void>() + return Subject.doAs(SecurityManager.getSystemTaskSubject(_virtualHostNodePrincipalName), new PrivilegedAction<Boolean>() { @Override - public Void run() + public Boolean run() { - processIntruderNode(node); - return null; + return processIntruderNode(node); + } }); } - private void processIntruderNode(ReplicationNode node) + private boolean processIntruderNode(ReplicationNode node) { String hostAndPort = node.getHostName() + ":" + node.getPort(); getEventLogger().message(getGroupLogSubject(), HighAvailabilityMessages.INTRUDER_DETECTED(node.getName(), hostAndPort)); @@ -864,11 +943,12 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu { addRemoteReplicationNode(node); } + return true; } else { - LOGGER.error(String.format("Intruder node '%s' from '%s' is detected. Stopping down virtual host node '%s'", - node.getName(), hostAndPort, BDBHAVirtualHostNodeImpl.this.toString() )); + LOGGER.error(String.format("Intruder node '%s' from '%s' detected. Shutting down virtual host node '%s' based on permitted nodes '%s'", + node.getName(), hostAndPort, BDBHAVirtualHostNodeImpl.this.getName(), String.valueOf(BDBHAVirtualHostNodeImpl.this.getPermittedNodes()) )); getTaskExecutor().submit(new Task<Void>() { @@ -876,13 +956,16 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu public Void execute() { State state = getState(); - if (state == State.ACTIVE) { try { stopAndSetStateTo(State.ERRORED); } + catch(Exception e) + { + LOGGER.error("Unexpected exception on closing the node when intruder is detected ", e); + } finally { closeEnvironment(); @@ -892,6 +975,7 @@ public class BDBHAVirtualHostNodeImpl extends AbstractVirtualHostNode<BDBHAVirtu return null; } }); + return false; } } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js index ed34bbbd7a..bd1812e86a 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/edit.js @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -define(["qpid/common/util", "qpid/common/metadata", "dijit/registry", "dojo/_base/window", "dojo/domReady!"], +define(["qpid/common/util", "qpid/common/metadata", "dijit/registry", "dojo/domReady!"], function (util, metadata, registry, win) { var fieldNames = ["storeUnderfullSize", "storeOverfullSize", @@ -28,120 +28,6 @@ define(["qpid/common/util", "qpid/common/metadata", "dijit/registry", "dojo/_bas registry.byId("editVirtualHost.storeUnderfullSize").set("regExpGen", util.numericOrContextVarRegexp); registry.byId("editVirtualHost.storeOverfullSize").set("regExpGen", util.numericOrContextVarRegexp); - - var that = this; - this.permittedNodes = registry.byId("editVirtualHost.permittedNodes"); - this.permittedNodesList = registry.byId("editVirtualHost.permittedNodesList"); - this.permittedNodesList.on("change", function(value){that._changePermittedNodeList(value);}); - - // permitted node text field - this.permittedNode = registry.byId("editVirtualHost.permittedNode"); - this.permittedNode.on("change", function(value){that._changePermittedNode(value);}); - - // add and remove buttons & click handlers - this.permittedNodeAddButton = registry.byId("editVirtualHost.permittedNodeAdd"); - this.permittedNodeAddButton.set("disabled", true); - this.permittedNodeRemoveButton = registry.byId("editVirtualHost.permittedNodeRemove"); - this.permittedNodeRemoveButton.set("disabled", true); - this.permittedNodeAddButton.on("click", function(e){that._clickAddPermittedNodeButton(e);}); - this.permittedNodeRemoveButton.on("click", function(e){that._clickRemovePermittedNodeButton(e);}); - - var permittedNodes = data.data.permittedNodes; - for(var i=0; i<permittedNodes.length;i++) - { - var host = permittedNodes[i]; - var newOption = this._addOption(host); - // add new option to list - this.permittedNodesList.containerNode.appendChild(newOption); - } - }, - _clickAddPermittedNodeButton: function(e) - { - // check the text box is valid and not empty - if(this.permittedNode.isValid() && - this.permittedNode.value && - this.permittedNode.value != "") - { - // read value to add from text box - var newAddress = this.permittedNode.value; - - // clear UI value - this.permittedNode.set("value", ""); - this.permittedNodeAddButton.set("disabled", true); - - //check entry not already present in list - var alreadyPresent = false; - var children = this.permittedNodesList.containerNode.children; - var i; - for (i = 0; i < children.length; i++) - { - var child = children.item(i); - if (child.value == newAddress) - { - alreadyPresent = true; - break; - } - } - - if (!alreadyPresent) - { - var newOption = this._addOption(newAddress); - - // add new option to list - this.permittedNodesList.containerNode.appendChild(newOption); - this._updatePermittedNodes(); - } - } - }, - _clickRemovePermittedNodeButton: function(e) - { - var selectedValues = this.permittedNodesList.get("value"); - var v; - for (v in selectedValues) - { - var children = this.permittedNodesList.containerNode.children; - var i; - for (i = 0; i < children.length; i++) - { - var child = children.item(i); - if (child.value == selectedValues[v]) - { - this.permittedNodesList.containerNode.removeChild(child); - } - } - } - this._updatePermittedNodes(); - this.permittedNodeRemoveButton.set("disabled", true); - }, - _addOption: function(newAddress) - { - // construct new option for list - var newOption = win.doc.createElement('option'); - newOption.innerHTML = newAddress; - newOption.value = newAddress; - return newOption; - }, - _changePermittedNodeList: function(value) - { - var hasSelection = this.permittedNodesList.get("value").length > 0; - this.permittedNodeRemoveButton.set("disabled", !hasSelection); - }, - _changePermittedNode: function(value) - { - var fieldIsEmpty = (this.permittedNode.get("value") == ""); - this.permittedNodeAddButton.set("disabled", fieldIsEmpty); - return true; - }, - _updatePermittedNodes: function() - { - var values = []; - var children = this.permittedNodesList.containerNode.children; - for (var i = 0; i < children.length; i++) - { - var child = children.item(i); - values.push(children.item(i).value); - } - this.permittedNodes.set("value", values); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js index f211d19d16..3bc3305e1f 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhost/bdb_ha/show.js @@ -28,7 +28,7 @@ define(["qpid/common/util", "dojo/query", "dojo/domReady!"], function BDB(data) { util.buildUI(data.containerNode, data.parent, "virtualhost/bdb_ha/show.html", fields, this); - this["permittedNodes"]= query(".permittedNodes", data.containerNode)[0]; + this[localTransactionSynchronizationPolicy]= query("." + localTransactionSynchronizationPolicy, data.containerNode)[0]; this[remoteTransactionSynchronizationPolicy]= query("."+ remoteTransactionSynchronizationPolicy, data.containerNode)[0]; } @@ -37,16 +37,6 @@ define(["qpid/common/util", "dojo/query", "dojo/domReady!"], { util.updateUI(data, fields, this); - var permittedNodesMarkup = ""; - if (data.permittedNodes) - { - for(var i=0;i<data.permittedNodes.length;i++) - { - permittedNodesMarkup+="<div>" + data.permittedNodes[i] + "</div>"; - } - } - this["permittedNodes"].innerHTML = permittedNodesMarkup ; - var localSyncPolicy = data[localTransactionSynchronizationPolicy] ? data[localTransactionSynchronizationPolicy].toLowerCase() : ""; var remoteSyncPolicy = data[remoteTransactionSynchronizationPolicy] ? data[remoteTransactionSynchronizationPolicy].toLowerCase() : ""; diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js index 30f47417aa..18853e63a7 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/add/newgroup/add.js @@ -67,7 +67,7 @@ define(["dojo/_base/xhr", this.addVirtualHostNodePermittedNodeRemoveButton.on("click", function(e){that._clickRemovePermittedNodeButton(e);}); // This will contain the serialised form that will go to the server - this.addVirtualHostNodeVirtualhostBlueprint = registry.byId("addVirtualHostNode.virtualhostBlueprint"); + this.addVirtualHostNodePermittedNodes = registry.byId("addVirtualHostNode.permittedNodes"); registry.byId("addVirtualHostNode.groupName").set("regExpGen", util.nameOrContextVarRegexp); }, @@ -90,7 +90,7 @@ define(["dojo/_base/xhr", } } - this.addVirtualHostNodeVirtualhostBlueprint.set("value",json.stringify({"permittedNodes" : permittedNodes})); + this.addVirtualHostNodePermittedNodes.set("value", permittedNodes); }, _changePermittedNodeList: function(value) { diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js index f2f256cd89..99b9209d8a 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/edit.js @@ -22,8 +22,9 @@ define(["qpid/common/util", "dijit/registry", "dojo/store/Memory", "dojo/data/ObjectStore", + "dojo/_base/window", "dojo/domReady!"], - function (util, registry, Memory, ObjectStore) + function (util, registry, Memory, ObjectStore, win) { var fields = [ "storePath", "name", "groupName", "address", "designatedPrimary", "priority", "quorumOverride"]; @@ -58,6 +59,120 @@ define(["qpid/common/util", } var store = new Memory({data :overrideData, idProperty: "id" }); registry.byId("editVirtualHostNode.quorumOverride").set("store", new ObjectStore({objectStore: store})); + + var that = this; + this.permittedNodes = registry.byId("editVirtualHostNode.permittedNodes"); + this.permittedNodesList = registry.byId("editVirtualHostNode.permittedNodesList"); + this.permittedNodesList.on("change", function(value){that._changePermittedNodeList(value);}); + + // permitted node text field + this.permittedNode = registry.byId("editVirtualHostNode.permittedNode"); + this.permittedNode.on("change", function(value){that._changePermittedNode(value);}); + + // add and remove buttons & click handlers + this.permittedNodeAddButton = registry.byId("editVirtualHostNode.permittedNodeAdd"); + this.permittedNodeAddButton.set("disabled", true); + this.permittedNodeRemoveButton = registry.byId("editVirtualHostNode.permittedNodeRemove"); + this.permittedNodeRemoveButton.set("disabled", true); + this.permittedNodeAddButton.on("click", function(e){that._clickAddPermittedNodeButton(e);}); + this.permittedNodeRemoveButton.on("click", function(e){that._clickRemovePermittedNodeButton(e);}); + + var permittedNodes = data.data.permittedNodes; + for(var i=0; i<permittedNodes.length;i++) + { + var host = permittedNodes[i]; + var newOption = this._addOption(host); + // add new option to list + this.permittedNodesList.containerNode.appendChild(newOption); + } + }, + _clickAddPermittedNodeButton: function(e) + { + // check the text box is valid and not empty + if(this.permittedNode.isValid() && + this.permittedNode.value && + this.permittedNode.value != "") + { + // read value to add from text box + var newAddress = this.permittedNode.value; + + // clear UI value + this.permittedNode.set("value", ""); + this.permittedNodeAddButton.set("disabled", true); + + //check entry not already present in list + var alreadyPresent = false; + var children = this.permittedNodesList.containerNode.children; + var i; + for (i = 0; i < children.length; i++) + { + var child = children.item(i); + if (child.value == newAddress) + { + alreadyPresent = true; + break; + } + } + + if (!alreadyPresent) + { + var newOption = this._addOption(newAddress); + + // add new option to list + this.permittedNodesList.containerNode.appendChild(newOption); + this._updatePermittedNodes(); + } + } + }, + _clickRemovePermittedNodeButton: function(e) + { + var selectedValues = this.permittedNodesList.get("value"); + var v; + for (v in selectedValues) + { + var children = this.permittedNodesList.containerNode.children; + var i; + for (i = 0; i < children.length; i++) + { + var child = children.item(i); + if (child.value == selectedValues[v]) + { + this.permittedNodesList.containerNode.removeChild(child); + } + } + } + this._updatePermittedNodes(); + this.permittedNodeRemoveButton.set("disabled", true); + }, + _addOption: function(newAddress) + { + // construct new option for list + var newOption = win.doc.createElement('option'); + newOption.innerHTML = newAddress; + newOption.value = newAddress; + return newOption; + }, + _changePermittedNodeList: function(value) + { + var hasSelection = this.permittedNodesList.get("value").length > 0; + this.permittedNodeRemoveButton.set("disabled", !hasSelection); + }, + _changePermittedNode: function(value) + { + var fieldIsEmpty = (this.permittedNode.get("value") == ""); + this.permittedNodeAddButton.set("disabled", fieldIsEmpty); + return true; + }, + _updatePermittedNodes: function() + { + var values = []; + var children = this.permittedNodesList.containerNode.children; + for (var i = 0; i < children.length; i++) + { + var child = children.item(i); + values.push(children.item(i).value); + } + this.permittedNodes.set("value", values); } }; } diff --git a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js index d914e16dc9..4997b16bc6 100644 --- a/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js +++ b/qpid/java/bdbstore/src/main/java/resources/js/qpid/management/virtualhostnode/bdb_ha/show.js @@ -90,7 +90,7 @@ define(["dojo/_base/xhr", this.designatedPrimaryContainer = findNode("designatedPrimaryContainer", containerNode); this.priorityContainer = findNode("priorityContainer", containerNode); this.quorumOverrideContainer = findNode("quorumOverrideContainer", containerNode); - + this.permittedNodes = query(".permittedNodes", containerNode)[0]; this.membersGridPanel = registry.byNode(query(".membersGridPanel", containerNode)[0]); this.membersGrid = new UpdatableStore([], findNode("groupMembers", containerNode), @@ -158,6 +158,18 @@ define(["dojo/_base/xhr", BDBHA.prototype.update=function(data) { this.parent.editNodeButton.set("disabled", false); + + + var permittedNodesMarkup = ""; + if (data.permittedNodes) + { + for(var i=0;i<data.permittedNodes.length;i++) + { + permittedNodesMarkup+="<div>" + data.permittedNodes[i] + "</div>"; + } + } + this.permittedNodes.innerHTML = permittedNodesMarkup ; + this.data = data; for(var i = 0; i < nodeFields.length; i++) { diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html b/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html index 9d0b0ab860..f4bf0c3c03 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/edit.html @@ -45,45 +45,6 @@ </div> </div> - <div class="formBox clear"> - <fieldset> - <legend>Permitted group nodes</legend> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Permitted addresses*:</div> - <div class="formLabel-controlCell tableContainer-valueCell addPermittedNodeList"> - <select type="text" id="editVirtualHost.permittedNodesList" - data-dojo-type="dijit/form/MultiSelect" - data-dojo-props=" - multiple: true, - name: 'permittedNodeList', - readOnly : 'true', - excluded: true, - title: 'Enter permitted nodes'"> - </select> <!-- must use closing tag rather than shorthand - dojo bug? --> - <input type="hidden" id="editVirtualHost.permittedNodes" - data-dojo-type="dijit/form/ValidationTextBox" - name="permittedNodes"/> - </div> - <button data-dojo-type="dijit/form/Button" id="editVirtualHost.permittedNodeRemove" data-dojo-props="label: '-'" ></button> - </div> - - <div class="clear"></div> - <div class="clear"> - <div class="formLabel-labelCell tableContainer-labelCell">Address:</div> - <div class="formLabel-controlCell tableContainer-valueCell"> - <input type="text" id="editVirtualHost.permittedNode" - data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props=" - name: 'permittedNode', - placeHolder: 'host:port', - intermediateChanges: true, - title: 'Enter address of node to be permitted into the group', - promptMessage: 'Address of node to be permitted into the group'" /> - </div> - <button data-dojo-type="dijit/form/Button" id="editVirtualHost.permittedNodeAdd" data-dojo-props="label: '+'"></button> - </div> - </fieldset> - </div> <div class="clear"></div> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/show.html b/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/show.html index 0c419aabae..d96942cd2d 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/show.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhost/bdb_ha/show.html @@ -26,10 +26,6 @@ <div class="formLabel-labelCell">Store underfull size:</div> <div><span class="storeUnderfullSize"></span> bytes</div> </div> - <div class="clear"> - <div class="formLabel-labelCell">Permitted nodes:</div> - <div class="permittedNodes multiLineValue"></div> - </div> <div class="clear"></div> <br/> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html index c25bae3419..7f7fb53ed8 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/add/newgroup/add.html @@ -91,10 +91,10 @@ </fieldset> </div> - <input type="hidden" id="addVirtualHostNode.virtualhostBlueprint" + <input type="hidden" id="addVirtualHostNode.permittedNodes" data-dojo-type="dijit/form/ValidationTextBox" - data-dojo-props="name: 'virtualhostBlueprint'" - contextvar="true"/> + data-dojo-props="name: 'permittedNodes'" + /> <input type="hidden" id="addVirtualHostNode.helperAddress" data-dojo-type="dijit/form/ValidationTextBox" diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html index f163390fa2..e040420bdb 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/edit.html @@ -53,6 +53,47 @@ </div> </div> + + <div class="formBox clear"> + <fieldset> + <legend>Permitted group nodes</legend> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Permitted addresses*:</div> + <div class="formLabel-controlCell tableContainer-valueCell addPermittedNodeList"> + <select type="text" id="editVirtualHostNode.permittedNodesList" + data-dojo-type="dijit/form/MultiSelect" + data-dojo-props=" + multiple: true, + name: 'permittedNodeList', + readOnly : 'true', + excluded: true, + title: 'Enter permitted nodes'"> + </select> <!-- must use closing tag rather than shorthand - dojo bug? --> + <input type="hidden" id="editVirtualHostNode.permittedNodes" + data-dojo-type="dijit/form/ValidationTextBox" + name="permittedNodes"/> + </div> + <button data-dojo-type="dijit/form/Button" id="editVirtualHostNode.permittedNodeRemove" data-dojo-props="label: '-'" ></button> + </div> + + <div class="clear"></div> + <div class="clear"> + <div class="formLabel-labelCell tableContainer-labelCell">Address:</div> + <div class="formLabel-controlCell tableContainer-valueCell"> + <input type="text" id="editVirtualHostNode.permittedNode" + data-dojo-type="dijit/form/ValidationTextBox" + data-dojo-props=" + name: 'permittedNode', + placeHolder: 'host:port', + intermediateChanges: true, + title: 'Enter address of node to be permitted into the group', + promptMessage: 'Address of node to be permitted into the group'" /> + </div> + <button data-dojo-type="dijit/form/Button" id="editVirtualHostNode.permittedNodeAdd" data-dojo-props="label: '+'"></button> + </div> + </fieldset> + </div> + <div class="clear"> <div class="formLabel-labelCell tableContainer-labelCell">Allow this node to operate solo: </div> <div class="formLabel-controlCell tableContainer-valueCell"> diff --git a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/show.html b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/show.html index 5a60b75c5c..690440cf7b 100644 --- a/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/show.html +++ b/qpid/java/bdbstore/src/main/java/resources/virtualhostnode/bdb_ha/show.html @@ -35,6 +35,10 @@ <div class="formLabel-labelCell">Address:</div> <div class="address">N/A</div> </div> + <div class="clear"> + <div class="formLabel-labelCell">Permitted nodes:</div> + <div class="permittedNodes multiLineValue"></div> + </div> <div class="clear designatedPrimaryContainer"> <div class="formLabel-labelCell">Allow this node to operate solo:</div> <div class="designatedPrimary">N/A</div> @@ -49,6 +53,7 @@ <span class="quorumOverride" >N/A</span> </div> </div> + <br/> <div class="clear"></div> <div data-dojo-type="dijit.TitlePane" data-dojo-props="title: 'Group nodes'" class="membersGridPanel"> <div class="groupMembers"></div> 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 e69000ecd1..7b03539625 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 @@ -401,11 +401,9 @@ public class BDBHAVirtualHostNodeTest extends QpidTestCase }; node1.addChangeListener(listener); - BDBHAVirtualHost<?> host = (BDBHAVirtualHost<?>)node1.getVirtualHost(); - List<String> permittedNodes = new ArrayList<String>(); permittedNodes.add(helperAddress); - host.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHost.PERMITTED_NODES, permittedNodes)); + node1.setAttributes(Collections.<String, Object>singletonMap(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes)); assertTrue("Intruder protection was not triggered during expected timeout", stopLatch.await(10, TimeUnit.SECONDS)); diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java index 5ed533f1e5..fcc8842619 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/ReplicatedEnvironmentFacadeTest.java @@ -32,7 +32,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import org.apache.log4j.Logger; -import org.apache.qpid.server.configuration.IllegalConfigurationException; import org.apache.qpid.server.store.berkeleydb.EnvironmentFacade; import org.apache.qpid.test.utils.QpidTestCase; import org.apache.qpid.test.utils.TestFileUtils; @@ -694,9 +693,10 @@ public class ReplicatedEnvironmentFacadeTest extends QpidTestCase ReplicationGroupListener listener = new NoopReplicationGroupListener() { @Override - public void onIntruderNode(ReplicationNode node) + public boolean onIntruderNode(ReplicationNode node) { intruderLatch.countDown(); + return true; } }; ReplicatedEnvironmentFacade firstNode = createMaster(listener); @@ -713,42 +713,6 @@ public class ReplicatedEnvironmentFacadeTest extends QpidTestCase assertTrue("Intruder node was not detected", intruderLatch.await(10, TimeUnit.SECONDS)); } - public void testIntruderNodeDetectionOnMasterAndReplicaNodes() throws Exception - { - final CountDownLatch intruderLatch = new CountDownLatch(2); - ReplicationGroupListener listener = new NoopReplicationGroupListener() - { - @Override - public void onIntruderNode(ReplicationNode node) - { - intruderLatch.countDown(); - } - }; - - ReplicatedEnvironmentFacade firstNode = createMaster(listener); - int replica1Port = getNextAvailable(TEST_NODE_PORT + 1); - String node2NodeHostPort = "localhost:" + replica1Port; - String nodeName2 = TEST_NODE_NAME + "_1"; - ReplicatedEnvironmentFacade secondNode = createReplica(nodeName2, node2NodeHostPort, listener); - - Set<String> permittedNodes = new HashSet<String>(); - permittedNodes.add("localhost:" + TEST_NODE_PORT); - permittedNodes.add(nodeName2); - firstNode.setPermittedNodes(permittedNodes); - - int counter = 0; - while(secondNode.getPermittedNodes().isEmpty() && counter < 100) - { - counter++; - Thread.sleep(50); - } - assertEquals("Permitted nodes are not set on a replica", permittedNodes, secondNode.getPermittedNodes()); - - int intruderPort = getNextAvailable(replica1Port+ 1); - createIntruder("intruder", "localhost:" + intruderPort); - assertTrue("Intruder node was not detected", intruderLatch.await(10, TimeUnit.SECONDS)); - } - private void createIntruder(String nodeName, String node1NodeHostPort) { File environmentPathFile = new File(_storePath, nodeName); @@ -872,9 +836,10 @@ public class ReplicatedEnvironmentFacadeTest extends QpidTestCase } @Override - public void onIntruderNode(ReplicationNode node) + public boolean onIntruderNode(ReplicationNode node) { LOGGER.warn("Intruder node " + node); + return true; } @Override diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java index ea7d74090d..1937eefc0b 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeOperationalLoggingTest.java @@ -300,6 +300,7 @@ public class BDBHAVirtualHostNodeOperationalLoggingTest extends QpidTestCase reset(_eventLogger); + node2Attributes.put(BDBHAVirtualHostNode.PERMITTED_NODES, node1Attributes.get(BDBHAVirtualHostNode.PERMITTED_NODES)); node2 = (BDBHAVirtualHostNodeImpl)_helper.recoverHaVHN(node2.getId(), node2Attributes); _helper.assertNodeRole(node2, "REPLICA", "MASTER"); waitForNodeDetachedField(remoteNode, false); diff --git a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java index 41c6c9a71c..6f18878a1d 100644 --- a/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java +++ b/qpid/java/bdbstore/src/test/java/org/apache/qpid/server/virtualhostnode/berkeleydb/BDBHAVirtualHostNodeTestHelper.java @@ -54,7 +54,6 @@ import org.apache.qpid.server.model.VirtualHostNode; import org.apache.qpid.server.store.ConfiguredObjectRecordImpl; import org.apache.qpid.server.store.UnresolvedConfiguredObject; import org.apache.qpid.server.util.BrokerTestHelper; -import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; import org.apache.qpid.test.utils.QpidTestCase; @@ -240,7 +239,8 @@ public class BDBHAVirtualHostNodeTestHelper iterationCounter++; } while(!inRole && iterationCounter<100); - assertTrue("Node " + node.getName() + " did not transit into role " + Arrays.toString(roleName), inRole); + assertTrue("Node " + node.getName() + " did not transit into role " + Arrays.toString(roleName) + + " Node role is " + node.getRole(), inRole); } public BDBHAVirtualHostNode<?> createAndStartHaVHN(Map<String, Object> attributes) throws InterruptedException @@ -280,6 +280,10 @@ public class BDBHAVirtualHostNodeTestHelper node1Attributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, helperAddress); node1Attributes.put(BDBHAVirtualHostNode.STORE_PATH, getMessageStorePath() + File.separator + nodeName); node1Attributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, helperNodeNode); + if (address.equals(helperAddress)) + { + node1Attributes.put(BDBHAVirtualHostNode.PERMITTED_NODES, getPermittedNodes(ports)); + } Map<String, String> context = new HashMap<String, String>(); context.put(ReplicationConfig.REPLICA_ACK_TIMEOUT, "2 s"); @@ -287,7 +291,7 @@ public class BDBHAVirtualHostNodeTestHelper if (ports != null) { - String bluePrint = getBlueprint(ports); + String bluePrint = getBlueprint(); node1Attributes.put(AbstractVirtualHostNode.VIRTUALHOST_INITIAL_CONFIGURATION, bluePrint); } @@ -296,16 +300,10 @@ public class BDBHAVirtualHostNodeTestHelper return node1Attributes; } - public static String getBlueprint(int... ports) throws Exception + public static String getBlueprint() throws Exception { - List<String> permittedNodes = new ArrayList<String>(); - for (int port:ports) - { - permittedNodes.add("localhost:" + port); - } Map<String,Object> bluePrint = new HashMap<>(); bluePrint.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); - bluePrint.put(BDBHAVirtualHost.PERMITTED_NODES, permittedNodes); StringWriter writer = new StringWriter(); ObjectMapper mapper = new ObjectMapper(); @@ -314,6 +312,16 @@ public class BDBHAVirtualHostNodeTestHelper return writer.toString(); } + public static List<String> getPermittedNodes(int[] ports) + { + List<String> permittedNodes = new ArrayList<String>(); + for (int port:ports) + { + permittedNodes.add("localhost:" + port); + } + return permittedNodes; + } + public void awaitForVirtualhost(final VirtualHostNode<?> node, final int wait) { long endTime = System.currentTimeMillis() + wait; diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java index 301375d0fb..fcbd210311 100644 --- a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostNodeRestTest.java @@ -226,7 +226,7 @@ public class BDBHAVirtualHostNodeRestTest extends QpidRestTestCase assertEquals("Unexpected number of remote nodes on " + NODE2, 1, data.size()); } - public void testIntruderBDBHAVHNNotAllowedNoConnect() throws Exception + public void testIntruderBDBHAVHNNotAllowedToConnect() throws Exception { createHANode(NODE1, _node1HaPort, _node1HaPort); assertNode(NODE1, _node1HaPort, _node1HaPort, NODE1); @@ -304,6 +304,7 @@ public class BDBHAVirtualHostNodeRestTest extends QpidRestTestCase intruder.close(); } } + waitForAttributeChanged(_baseNodeRestUrl + NODE1, VirtualHostNode.STATE, State.ERRORED.name()); waitForAttributeChanged(_baseNodeRestUrl + NODE3, VirtualHostNode.STATE, State.ERRORED.name()); } @@ -329,7 +330,11 @@ public class BDBHAVirtualHostNodeRestTest extends QpidRestTestCase nodeData.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, NODE1); Map<String,String> context = new HashMap<>(); nodeData.put(BDBHAVirtualHostNode.CONTEXT, context); - String bluePrint = GroupCreator.getBlueprint("localhost", _node1HaPort, _node2HaPort, _node3HaPort); + if (nodePort == helperPort) + { + nodeData.put(BDBHAVirtualHostNode.PERMITTED_NODES, GroupCreator.getPermittedNodes("localhost", _node1HaPort, _node2HaPort, _node3HaPort)); + } + String bluePrint = GroupCreator.getBlueprint(); context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, bluePrint); return nodeData; } diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java index 07ce033a55..f73a2878d3 100644 --- a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/BDBHAVirtualHostRestTest.java @@ -27,6 +27,7 @@ import java.io.File; import java.io.IOException; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletResponse; @@ -49,6 +50,8 @@ public class BDBHAVirtualHostRestTest extends QpidRestTestCase private Object _nodeName; private String _virtualhostUrl; private String _bluePrint; + private List<String> _permittedNodes; + private String _address; @Override public void setUp() throws Exception @@ -59,8 +62,9 @@ public class BDBHAVirtualHostRestTest extends QpidRestTestCase _storeBaseDir = new File(TMP_FOLDER, "store-" + _hostName + "-" + System.currentTimeMillis()); _nodeHaPort = getNextAvailable(getRestTestHelper().getHttpPort() + 1); _virtualhostUrl = "virtualhost/" + _nodeName + "/" + _hostName; - _bluePrint = GroupCreator.getBlueprint("localhost", _nodeHaPort); - + _bluePrint = GroupCreator.getBlueprint(); + _permittedNodes = GroupCreator.getPermittedNodes("localhost", _nodeHaPort); + _address = "localhost:" + _nodeHaPort; super.setUp(); } @@ -93,9 +97,11 @@ public class BDBHAVirtualHostRestTest extends QpidRestTestCase nodeAttributes.put(BDBHAVirtualHostNode.TYPE, "BDB_HA"); nodeAttributes.put(BDBHAVirtualHostNode.STORE_PATH, _storeBaseDir.getPath() + File.separator + _nodeName); nodeAttributes.put(BDBHAVirtualHostNode.GROUP_NAME, _hostName); - nodeAttributes.put(BDBHAVirtualHostNode.ADDRESS, "localhost:" + _nodeHaPort); + nodeAttributes.put(BDBHAVirtualHostNode.ADDRESS, _address); nodeAttributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, "localhost:" + _nodeHaPort); nodeAttributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, _nodeName); + + nodeAttributes.put(BDBHAVirtualHostNode.PERMITTED_NODES, _permittedNodes); Map<String, String> context = new HashMap<String,String>(); context.put(AbstractVirtualHostNode.VIRTUALHOST_BLUEPRINT_CONTEXT_VAR, _bluePrint); diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java index f7dce4f3f5..673e492d52 100644 --- a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/GroupCreator.java @@ -52,7 +52,6 @@ import org.apache.qpid.server.model.Plugin; import org.apache.qpid.server.model.Port; import org.apache.qpid.server.model.VirtualHost; import org.apache.qpid.server.model.VirtualHostNode; -import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHost; import org.apache.qpid.server.virtualhost.berkeleydb.BDBHAVirtualHostImpl; import org.apache.qpid.server.virtualhostnode.AbstractVirtualHostNode; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHARemoteReplicationNode; @@ -118,7 +117,8 @@ public class GroupCreator brokerPort = _testcase.getNextAvailable(bdbPort + 1); } - String bluePrintJson = getBlueprint(_ipAddressOfBroker, bdbPorts); + String bluePrintJson = getBlueprint(); + List<String> permittedNodes = getPermittedNodes(_ipAddressOfBroker, bdbPorts); String helperName = null; for (Map.Entry<Integer,Integer> entry: _brokerPortToBdbPortMap.entrySet()) @@ -145,6 +145,7 @@ public class GroupCreator virtualHostNodeAttributes.put(BDBHAVirtualHostNode.HELPER_ADDRESS, getHelperHostPort()); virtualHostNodeAttributes.put(BDBHAVirtualHostNode.TYPE, BDBHAVirtualHostNodeImpl.VIRTUAL_HOST_NODE_TYPE); virtualHostNodeAttributes.put(BDBHAVirtualHostNode.HELPER_NODE_NAME, helperName); + virtualHostNodeAttributes.put(BDBHAVirtualHostNode.PERMITTED_NODES, permittedNodes); Map<String, String> context = new HashMap<>(); context.put(ReplicationConfig.INSUFFICIENT_REPLICAS_TIMEOUT, "2 s"); @@ -365,11 +366,6 @@ public class GroupCreator return _ipAddressOfBroker + ":" + _bdbHelperPort; } - public void setHelperHostPort(int bdbHelperPort) - { - _bdbHelperPort = bdbHelperPort; - } - public int getBrokerPortNumberOfPrimary() { if (_numberOfNodes != 2) @@ -406,21 +402,6 @@ public class GroupCreator } } - public void modifyClusterNodeBdbAddress(int brokerPortNumberToBeMoved, int newBdbPort) - { - TestBrokerConfiguration config = _testcase.getBrokerConfiguration(brokerPortNumberToBeMoved); - String nodeName = getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(brokerPortNumberToBeMoved)); - - Map<String, Object> objectAttributes = config.getObjectAttributes(VirtualHostNode.class, nodeName); - - String oldBdbHostPort = (String)objectAttributes.get(BDBHAVirtualHostNode.ADDRESS); - String[] oldHostAndPort = StringUtils.split(oldBdbHostPort, ":"); - String oldHost = oldHostAndPort[0]; - String newBdbHostPort = oldHost + ":" + newBdbPort; - config.setObjectAttribute(VirtualHostNode.class, nodeName, BDBHAVirtualHostNode.ADDRESS, newBdbHostPort); - config.setSaved(false); - } - public String getNodeNameForBrokerPort(final int brokerPort) { return getNodeNameForNodeAt(_brokerPortToBdbPortMap.get(brokerPort)); @@ -491,20 +472,25 @@ public class GroupCreator public void awaitNodeToAttainRole(int localNodePort, int remoteNodePort, String desiredRole) throws Exception { + awaitNodeToAttainAttributeValue(localNodePort, remoteNodePort, BDBHARemoteReplicationNode.ROLE, desiredRole); + } + + public void awaitNodeToAttainAttributeValue(int localNodePort, int remoteNodePort, String attributeName, String desiredValue) throws Exception + { final long startTime = System.currentTimeMillis(); Map<String, Object> data = Collections.emptyMap(); - while(!desiredRole.equals(data.get(BDBHARemoteReplicationNode.ROLE)) && (System.currentTimeMillis() - startTime) < 30000) + while(!desiredValue.equals(data.get(attributeName)) && (System.currentTimeMillis() - startTime) < 30000) { - LOGGER.debug("Awaiting node '" + getNodeNameForBrokerPort(remoteNodePort) + "' to transit into " + desiredRole + " role"); + LOGGER.debug("Awaiting node '" + getNodeNameForBrokerPort(remoteNodePort) + "' to transit into " + desiredValue + " role"); data = getNodeAttributes(localNodePort, remoteNodePort); - if (!desiredRole.equals(data.get(BDBHARemoteReplicationNode.ROLE))) + if (!desiredValue.equals(data.get(attributeName))) { Thread.sleep(1000); } } - LOGGER.debug("Node '" + getNodeNameForBrokerPort(remoteNodePort) + "' role is " + data.get(BDBHARemoteReplicationNode.ROLE)); - Assert.assertEquals("Node is in unexpected role", desiredRole, data.get(BDBHARemoteReplicationNode.ROLE)); + LOGGER.debug("Node '" + getNodeNameForBrokerPort(remoteNodePort) + "' attribute '" + attributeName + "' is " + data.get(attributeName)); + Assert.assertEquals("Unexpected " + attributeName + " at " + localNodePort, desiredValue, data.get(attributeName)); } public RestTestHelper createRestTestHelper(int brokerPort) @@ -515,16 +501,10 @@ public class GroupCreator return helper; } - public static String getBlueprint(String hostName, int... ports) throws Exception + public static String getBlueprint() throws Exception { - List<String> permittedNodes = new ArrayList<String>(); - for (int port:ports) - { - permittedNodes.add(hostName + ":" + port); - } Map<String,Object> bluePrint = new HashMap<>(); bluePrint.put(VirtualHost.TYPE, BDBHAVirtualHostImpl.VIRTUAL_HOST_TYPE); - bluePrint.put(BDBHAVirtualHost.PERMITTED_NODES, permittedNodes); StringWriter writer = new StringWriter(); ObjectMapper mapper = new ObjectMapper(); @@ -532,4 +512,14 @@ public class GroupCreator mapper.writeValue(writer, bluePrint); return writer.toString(); } + + public static List<String> getPermittedNodes(String hostName, int... ports) + { + List<String> permittedNodes = new ArrayList<String>(); + for (int port: ports) + { + permittedNodes.add(hostName + ":" + port); + } + return permittedNodes; + } } diff --git a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java index d6ba419de1..5701c8c9c8 100644 --- a/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java +++ b/qpid/java/bdbstore/systests/src/test/java/org/apache/qpid/server/store/berkeleydb/replication/MultiNodeTest.java @@ -33,10 +33,15 @@ import javax.jms.Message; import javax.jms.MessageConsumer; import javax.jms.Session; +import com.sleepycat.je.Durability; +import com.sleepycat.je.EnvironmentConfig; +import com.sleepycat.je.rep.ReplicatedEnvironment; +import com.sleepycat.je.rep.ReplicationConfig; import org.apache.log4j.Logger; import org.apache.qpid.client.AMQConnection; import org.apache.qpid.jms.ConnectionListener; import org.apache.qpid.jms.ConnectionURL; +import org.apache.qpid.server.model.State; import org.apache.qpid.server.virtualhostnode.berkeleydb.BDBHAVirtualHostNode; import org.apache.qpid.test.utils.QpidBrokerTestCase; import org.apache.qpid.test.utils.TestUtils; @@ -320,6 +325,47 @@ public class MultiNodeTest extends QpidBrokerTestCase assertProducingConsuming(connection); } + public void testClusterCannotStartWithIntruder() throws Exception + { + int intruderPort = getNextAvailable(Collections.max(_groupCreator.getBdbPortNumbers()) + 1); + String nodeName = "intruder"; + String nodeHostPort = _groupCreator.getIpAddressOfBrokerHost() + ":" + intruderPort; + File environmentPathFile = new File(System.getProperty("QPID_WORK"), intruderPort + ""); + environmentPathFile.mkdirs(); + ReplicationConfig replicationConfig = new ReplicationConfig(_groupCreator.getGroupName(), nodeName, nodeHostPort); + replicationConfig.setHelperHosts(_groupCreator.getHelperHostPort()); + EnvironmentConfig envConfig = new EnvironmentConfig(); + envConfig.setAllowCreate(true); + envConfig.setTransactional(true); + envConfig.setDurability(new Durability(Durability.SyncPolicy.SYNC, Durability.SyncPolicy.WRITE_NO_SYNC, Durability.ReplicaAckPolicy.SIMPLE_MAJORITY)); + + ReplicatedEnvironment intruder = null; + try + { + intruder = new ReplicatedEnvironment(environmentPathFile, replicationConfig, envConfig); + } + finally + { + if (intruder != null) + { + intruder.close(); + } + } + + for (int port: _groupCreator.getBrokerPortNumbersForNodes()) + { + _groupCreator.awaitNodeToAttainAttributeValue(port, port, BDBHAVirtualHostNode.STATE, State.ERRORED.name()); + } + + _groupCreator.stopCluster(); + _groupCreator.startCluster(); + + for (int port: _groupCreator.getBrokerPortNumbersForNodes()) + { + _groupCreator.awaitNodeToAttainAttributeValue(port, port, BDBHAVirtualHostNode.STATE, State.ERRORED.name()); + } + } + private final class FailoverAwaitingListener implements ConnectionListener { private final CountDownLatch _failoverCompletionLatch = new CountDownLatch(1); |