Repository: asterixdb Updated Branches: refs/heads/master 2b5aa0f53 -> cf4f7f7be
[ASTERIXDB-2435][*DB][CLUS] Block unknown nodes Provide mechanism by which unauthorized nodes can be prevented from joining hyracks cluster. In *DB, only authorize configured nodes to join. Change-Id: I3a45a41f69e8e9968dd65bb2268d3d3a2ced9664 Reviewed-on: https://asterix-gerrit.ics.uci.edu/2851 Sonar-Qube: Jenkins <[email protected]> Tested-by: Jenkins <[email protected]> Reviewed-by: Murtadha Hubail <[email protected]> Contrib: Jenkins <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/asterixdb/repo Commit: http://git-wip-us.apache.org/repos/asf/asterixdb/commit/cf4f7f7b Tree: http://git-wip-us.apache.org/repos/asf/asterixdb/tree/cf4f7f7b Diff: http://git-wip-us.apache.org/repos/asf/asterixdb/diff/cf4f7f7b Branch: refs/heads/master Commit: cf4f7f7be46ea07ab395bb9b535d80fa4c3ad6d3 Parents: 2b5aa0f Author: Michael Blow <[email protected]> Authored: Tue Aug 7 07:33:00 2018 -0700 Committer: Michael Blow <[email protected]> Committed: Tue Aug 7 08:47:06 2018 -0700 ---------------------------------------------------------------------- .../hyracks/bootstrap/CCApplication.java | 6 ++++ .../hyracks/api/application/ICCApplication.java | 4 +++ .../apache/hyracks/api/control/IGatekeeper.java | 30 ++++++++++++++++++++ .../hyracks/control/cc/BaseCCApplication.java | 5 ++++ .../control/cc/ClusterControllerService.java | 2 +- .../hyracks/control/cc/cluster/NodeManager.java | 20 +++++++------ .../control/cc/cluster/NodeManagerTest.java | 30 +++++++++++++++++--- 7 files changed, 84 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java ---------------------------------------------------------------------- diff --git a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java index 5c05b2f..a5fd063 100644 --- a/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java +++ b/asterixdb/asterix-app/src/main/java/org/apache/asterix/hyracks/bootstrap/CCApplication.java @@ -86,6 +86,7 @@ import org.apache.hyracks.api.application.IServiceContext; import org.apache.hyracks.api.client.HyracksConnection; import org.apache.hyracks.api.client.IHyracksClientConnection; import org.apache.hyracks.api.config.IConfigManager; +import org.apache.hyracks.api.control.IGatekeeper; import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.api.job.resource.IJobCapacityController; import org.apache.hyracks.api.lifecycle.LifeCycleComponentManager; @@ -117,6 +118,7 @@ public class CCApplication extends BaseCCApplication { @Override public void init(IServiceContext serviceCtx) throws Exception { + super.init(serviceCtx); ccServiceCtx = (ICCServiceContext) serviceCtx; ccServiceCtx.setThreadFactory( new AsterixThreadFactory(ccServiceCtx.getThreadFactory(), new LifeCycleComponentManager())); @@ -354,4 +356,8 @@ public class CCApplication extends BaseCCApplication { ApplicationConfigurator.validateJavaRuntime(); } + @Override + public IGatekeeper getGatekeeper() { + return getConfigManager().getAppConfig().getNCNames()::contains; + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/application/ICCApplication.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/application/ICCApplication.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/application/ICCApplication.java index 6bcdd8a..aa1021b 100644 --- a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/application/ICCApplication.java +++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/application/ICCApplication.java @@ -19,6 +19,7 @@ package org.apache.hyracks.api.application; import org.apache.hyracks.api.config.IConfigManager; +import org.apache.hyracks.api.control.IGatekeeper; import org.apache.hyracks.api.job.resource.IJobCapacityController; public interface ICCApplication extends IApplication { @@ -26,4 +27,7 @@ public interface ICCApplication extends IApplication { IJobCapacityController getJobCapacityController(); IConfigManager getConfigManager(); + + IGatekeeper getGatekeeper(); + } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/control/IGatekeeper.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/control/IGatekeeper.java b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/control/IGatekeeper.java new file mode 100644 index 0000000..43c8143 --- /dev/null +++ b/hyracks-fullstack/hyracks/hyracks-api/src/main/java/org/apache/hyracks/api/control/IGatekeeper.java @@ -0,0 +1,30 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.hyracks.api.control; + +@FunctionalInterface +public interface IGatekeeper { + /** + * Indicates whether the supplied node is authorized to join this cluster + * @param nodeId + * the node to consider + * @return <code>true</code> if the supplied node is authorized + */ + boolean isAuthorized(String nodeId); +} http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/BaseCCApplication.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/BaseCCApplication.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/BaseCCApplication.java index dc63481..46adda3 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/BaseCCApplication.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/BaseCCApplication.java @@ -24,6 +24,7 @@ import org.apache.hyracks.api.application.ICCApplication; import org.apache.hyracks.api.application.IServiceContext; import org.apache.hyracks.api.config.IConfigManager; import org.apache.hyracks.api.config.Section; +import org.apache.hyracks.api.control.IGatekeeper; import org.apache.hyracks.api.job.resource.DefaultJobCapacityController; import org.apache.hyracks.api.job.resource.IJobCapacityController; import org.apache.hyracks.api.util.HyracksConstants; @@ -91,4 +92,8 @@ public class BaseCCApplication implements ICCApplication { return configManager; } + @Override + public IGatekeeper getGatekeeper() { + return node -> true; + } } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java index 8ed015c..ae82803 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/ClusterControllerService.java @@ -179,7 +179,7 @@ public class ClusterControllerService implements IControllerService { threadDumpRunMap = Collections.synchronizedMap(new HashMap<>()); // Node manager is in charge of cluster membership management. - nodeManager = new NodeManager(this, ccConfig, resourceManager); + nodeManager = new NodeManager(this, ccConfig, resourceManager, application.getGatekeeper()); ccId = ccConfig.getCcId(); jobIdFactory = new JobIdFactory(ccId); http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java index 31f989b..4f76ced 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/main/java/org/apache/hyracks/control/cc/cluster/NodeManager.java @@ -34,6 +34,7 @@ import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.tuple.Pair; import org.apache.hyracks.api.client.NodeControllerInfo; import org.apache.hyracks.api.client.NodeStatus; +import org.apache.hyracks.api.control.IGatekeeper; import org.apache.hyracks.api.exceptions.ErrorCode; import org.apache.hyracks.api.exceptions.HyracksDataException; import org.apache.hyracks.api.exceptions.HyracksException; @@ -45,8 +46,6 @@ import org.apache.hyracks.control.cc.job.IJobManager; import org.apache.hyracks.control.cc.job.JobRun; import org.apache.hyracks.control.cc.scheduler.IResourceManager; import org.apache.hyracks.control.common.controllers.CCConfig; -import org.apache.hyracks.control.common.ipc.CCNCFunctions.AbortCCJobsFunction; -import org.apache.hyracks.ipc.api.IIPCHandle; import org.apache.hyracks.ipc.exceptions.IPCException; import org.apache.hyracks.util.annotations.Idempotent; import org.apache.hyracks.util.annotations.NotThreadSafe; @@ -63,14 +62,17 @@ public class NodeManager implements INodeManager { private final Map<String, NodeControllerState> nodeRegistry; private final Map<InetAddress, Set<String>> ipAddressNodeNameMap; private final int nodeCoresMultiplier; + private final IGatekeeper gatekeeper; - public NodeManager(ClusterControllerService ccs, CCConfig ccConfig, IResourceManager resourceManager) { + public NodeManager(ClusterControllerService ccs, CCConfig ccConfig, IResourceManager resourceManager, + IGatekeeper gatekeeper) { this.ccs = ccs; this.ccConfig = ccConfig; this.resourceManager = resourceManager; this.nodeRegistry = new LinkedHashMap<>(); this.ipAddressNodeNameMap = new HashMap<>(); this.nodeCoresMultiplier = ccConfig.getCoresMultiplier(); + this.gatekeeper = gatekeeper; } @Override @@ -95,13 +97,16 @@ public class NodeManager implements INodeManager { @Override public synchronized void addNode(String nodeId, NodeControllerState ncState) throws HyracksException { - LOGGER.warn("addNode(" + nodeId + ") called"); + LOGGER.warn("+addNode: " + nodeId); if (nodeId == null || ncState == null) { throw HyracksException.create(ErrorCode.INVALID_INPUT_PARAMETER); } + if (!gatekeeper.isAuthorized(nodeId)) { + throw HyracksException.create(ErrorCode.NO_SUCH_NODE, nodeId); + } // Updates the node registry. if (nodeRegistry.containsKey(nodeId)) { - LOGGER.warn("Node with name " + nodeId + " has already registered; failing the node then re-registering."); + LOGGER.warn("Node '" + nodeId + "' is already registered; failing the node then re-registering."); failNode(nodeId); } try { @@ -109,7 +114,7 @@ public class NodeManager implements INodeManager { } catch (IPCException e) { throw HyracksDataException.create(e); } - LOGGER.warn("adding node to registry"); + LOGGER.info("adding node to registry"); nodeRegistry.put(nodeId, ncState); // Updates the IP address to node names map. try { @@ -121,8 +126,7 @@ public class NodeManager implements INodeManager { nodeRegistry.remove(nodeId); throw e; } - // Updates the cluster capacity. - LOGGER.warn("updating cluster capacity"); + LOGGER.info("updating cluster capacity"); resourceManager.update(nodeId, getAdjustedNodeCapacity(ncState.getCapacity())); } http://git-wip-us.apache.org/repos/asf/asterixdb/blob/cf4f7f7b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/cluster/NodeManagerTest.java ---------------------------------------------------------------------- diff --git a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/cluster/NodeManagerTest.java b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/cluster/NodeManagerTest.java index 43b00f3..9d755a0 100644 --- a/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/cluster/NodeManagerTest.java +++ b/hyracks-fullstack/hyracks/hyracks-control/hyracks-control-cc/src/test/java/org/apache/hyracks/control/cc/cluster/NodeManagerTest.java @@ -56,7 +56,7 @@ public class NodeManagerTest { final CCConfig ccConfig = makeCCConfig(); final int coresMultiplier = 1; ccConfig.setCoresMultiplier(coresMultiplier); - INodeManager nodeManager = new NodeManager(mockCcs(), ccConfig, resourceManager); + INodeManager nodeManager = new NodeManager(mockCcs(), ccConfig, resourceManager, nodeId -> true); NodeControllerState ncState1 = mockNodeControllerState(NODE1, false); NodeControllerState ncState2 = mockNodeControllerState(NODE2, false); @@ -84,7 +84,7 @@ public class NodeManagerTest { final CCConfig ccConfig = makeCCConfig(); final int coresMultiplier = 3; ccConfig.setCoresMultiplier(coresMultiplier); - INodeManager nodeManager = new NodeManager(mockCcs(), ccConfig, resourceManager); + INodeManager nodeManager = new NodeManager(mockCcs(), ccConfig, resourceManager, nodeId -> true); NodeControllerState ncState1 = mockNodeControllerState(NODE1, false); NodeControllerState ncState2 = mockNodeControllerState(NODE2, false); @@ -113,7 +113,7 @@ public class NodeManagerTest { @Test public void testException() throws HyracksException, IPCException { IResourceManager resourceManager = new ResourceManager(); - INodeManager nodeManager = new NodeManager(mockCcs(), makeCCConfig(), resourceManager); + INodeManager nodeManager = new NodeManager(mockCcs(), makeCCConfig(), resourceManager, nodeId -> true); NodeControllerState ncState1 = mockNodeControllerState(NODE1, true); boolean invalidNetworkAddress = false; @@ -142,7 +142,7 @@ public class NodeManagerTest { @Test public void testNullNode() throws HyracksException { IResourceManager resourceManager = new ResourceManager(); - INodeManager nodeManager = new NodeManager(null, makeCCConfig(), resourceManager); + INodeManager nodeManager = new NodeManager(null, makeCCConfig(), resourceManager, nodeId -> true); boolean invalidParameter = false; // Verifies states after a failure during adding nodes. @@ -217,4 +217,26 @@ public class NodeManagerTest { Assert.assertTrue(nodeNotExist); } + @Test + public void testUnauthorized() throws HyracksException, IPCException { + IResourceManager resourceManager = new ResourceManager(); + final CCConfig ccConfig = makeCCConfig(); + INodeManager nodeManager = new NodeManager(mockCcs(), ccConfig, resourceManager, NODE1::equals); + NodeControllerState ncState1 = mockNodeControllerState(NODE1, false); + NodeControllerState ncState2 = mockNodeControllerState(NODE2, false); + + nodeManager.addNode(NODE1, ncState1); + boolean nodeNotExist = false; + try { + nodeManager.addNode(NODE2, ncState2); + } catch (HyracksException e) { + nodeNotExist = e.getErrorCode() == ErrorCode.NO_SUCH_NODE; + } + Assert.assertTrue(nodeNotExist); + Assert.assertTrue(nodeManager.getIpAddressNodeNameMap().size() == 1); + Assert.assertTrue(nodeManager.getAllNodeIds().size() == 1); + Assert.assertTrue(nodeManager.getAllNodeControllerStates().size() == 1); + Assert.assertTrue(nodeManager.getNodeControllerState(NODE1) == ncState1); + } + }
