diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java index 9f4ae1d8c79..93ad906eace 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/AdminService.java @@ -738,7 +738,7 @@ public RefreshNodesResourcesResponse refreshNodesResources( } } - private synchronized Configuration getConfiguration(Configuration conf, + public synchronized Configuration getConfiguration(Configuration conf, String... confFileNames) throws YarnException, IOException { for (String confFileName : confFileNames) { InputStream confFileInputStream = diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacityScheduler.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacityScheduler.java index fcc05602871..709ddb4eb26 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacityScheduler.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacityScheduler.java @@ -183,6 +183,10 @@ private CapacitySchedulerQueueManager queueManager; + CapacitySchedulerQueueManager getQueueManager() { + return queueManager; + } + private WorkflowPriorityMappingsManager workflowPriorityMappingsMgr; // timeout to join when we stop this service @@ -207,40 +211,9 @@ public void setConf(Configuration conf) { private void validateConf(Configuration conf) { // validate scheduler memory allocation setting - int minMem = conf.getInt( - YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB, - YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB); - int maxMem = conf.getInt( - YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_MB, - YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_MB); - - if (minMem <= 0 || minMem > maxMem) { - throw new YarnRuntimeException("Invalid resource scheduler memory" - + " allocation configuration" - + ", " + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB - + "=" + minMem - + ", " + YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_MB - + "=" + maxMem + ", min and max should be greater than 0" - + ", max should be no smaller than min."); - } - + CapacitySchedulerConfigValidator.validateMemoryAllocation(conf); // validate scheduler vcores allocation setting - int minVcores = conf.getInt( - YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES, - YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES); - int maxVcores = conf.getInt( - YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES, - YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES); - - if (minVcores <= 0 || minVcores > maxVcores) { - throw new YarnRuntimeException("Invalid resource scheduler vcores" - + " allocation configuration" - + ", " + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES - + "=" + minVcores - + ", " + YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES - + "=" + maxVcores + ", min and max should be greater than 0" - + ", max should be no smaller than min."); - } + CapacitySchedulerConfigValidator.validateVCores(conf); } @Override @@ -488,7 +461,10 @@ public void reinitialize(Configuration newConf, RMContext rmContext) Configuration configuration = new Configuration(newConf); CapacitySchedulerConfiguration oldConf = this.conf; this.conf = csConfProvider.loadConfiguration(configuration); - validateConf(this.conf); + + CapacitySchedulerConfigValidator.validateMemoryAllocation(this.conf); + CapacitySchedulerConfigValidator.validateVCores(this.conf); + try { LOG.info("Re-initializing queues..."); refreshMaximumAllocation( @@ -714,19 +690,14 @@ public void updatePlacementRules() throws IOException { Collection placementRuleStrs = conf.getStringCollection( YarnConfiguration.QUEUE_PLACEMENT_RULES); List placementRules = new ArrayList<>(); - Set distingushRuleSet = new HashSet<>(); - // fail the case if we get duplicate placementRule add in - for (String pls : placementRuleStrs) { - if (!distingushRuleSet.add(pls)) { - throw new IOException("Invalid PlacementRule inputs which " - + "contains duplicate rule strings"); - } - } + CapacitySchedulerConfigValidator + .validatePlacementRules(placementRuleStrs); + Set distinguishRuleSet = new HashSet<>(placementRuleStrs); // add UserGroupMappingPlacementRule if absent - distingushRuleSet.add(YarnConfiguration.USER_GROUP_PLACEMENT_RULE); + distinguishRuleSet.add(YarnConfiguration.USER_GROUP_PLACEMENT_RULE); - placementRuleStrs = new ArrayList<>(distingushRuleSet); + placementRuleStrs = new ArrayList<>(distinguishRuleSet); for (String placementRuleStr : placementRuleStrs) { switch (placementRuleStr) { diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfigValidator.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfigValidator.java new file mode 100644 index 00000000000..15848a0fc3b --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerConfigValidator.java @@ -0,0 +1,202 @@ +/** + * 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.hadoop.yarn.server.resourcemanager.scheduler.capacity; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.yarn.api.records.QueueState; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.exceptions.YarnRuntimeException; +import org.apache.hadoop.yarn.server.resourcemanager.RMContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public final class CapacitySchedulerConfigValidator { + private static final Logger LOG = LoggerFactory.getLogger( + CapacitySchedulerConfigValidator.class); + + private CapacitySchedulerConfigValidator() { + + throw new IllegalStateException("Utility class"); + } + + public static boolean validateCSConfiguration(final Configuration conf, + final RMContext rmContext) throws IOException { + + validateMemoryAllocation(conf); + validateVCores(conf); + + CapacityScheduler newCs = new CapacityScheduler(); + newCs.setConf(conf); + newCs.setRMContext(rmContext); + newCs.init(conf); + CapacitySchedulerQueueManager qm = newCs.getQueueManager(); + + CapacitySchedulerConfiguration proposedConf = + new CapacitySchedulerConfiguration(conf, false); + qm.reinitializeQueues(proposedConf); + + Collection placementRuleStrs = conf.getStringCollection( + YarnConfiguration.QUEUE_PLACEMENT_RULES); + validatePlacementRules(placementRuleStrs); + + return true; + } + + public static Set validatePlacementRules + (Collection placementRuleStrs) throws IOException { + + Set distinguishRuleSet = new HashSet<>(); + // fail the case if we get duplicate placementRule add in + for (String pls : placementRuleStrs) { + if (!distinguishRuleSet.add(pls)) { + throw new IOException("Invalid PlacementRule inputs which " + + "contains duplicate rule strings"); + } + } + return distinguishRuleSet; + } + + public static void validateMemoryAllocation(Configuration conf) { + int minMem = conf.getInt( + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB, + YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_MB); + int maxMem = conf.getInt( + YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_MB, + YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_MB); + + if (minMem <= 0 || minMem > maxMem) { + throw new YarnRuntimeException("Invalid resource scheduler memory" + + " allocation configuration" + + ", " + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_MB + + "=" + minMem + + ", " + YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_MB + + "=" + maxMem + ", min and max should be greater than 0" + + ", max should be no smaller than min."); + } + } + public static void validateVCores(Configuration conf) { + int minVcores = conf.getInt( + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES, + YarnConfiguration.DEFAULT_RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES); + int maxVcores = conf.getInt( + YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES, + YarnConfiguration.DEFAULT_RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES); + + if (minVcores <= 0 || minVcores > maxVcores) { + throw new YarnRuntimeException("Invalid resource scheduler vcores" + + " allocation configuration" + + ", " + YarnConfiguration.RM_SCHEDULER_MINIMUM_ALLOCATION_VCORES + + "=" + minVcores + + ", " + YarnConfiguration.RM_SCHEDULER_MAXIMUM_ALLOCATION_VCORES + + "=" + maxVcores + ", min and max should be greater than 0" + + ", max should be no smaller than min."); + } + } + + /** + * Ensure all existing queues are present. Queues cannot be deleted if its not + * in Stopped state, Queue's cannot be moved from one hierarchy to other also. + * Previous child queue could be converted into parent queue if it is in + * STOPPED state. + * + * @param queues existing queues + * @param newQueues new queues + */ + public static void validateQueueHierarchy(Map queues, + Map newQueues, CapacitySchedulerConfiguration newConf) + throws IOException { + // check that all static queues are included in the newQueues list + for (Map.Entry e : queues.entrySet()) { + if (!(AbstractAutoCreatedLeafQueue.class.isAssignableFrom(e.getValue() + .getClass()))) { + String queueName = e.getKey(); + CSQueue oldQueue = e.getValue(); + CSQueue newQueue = newQueues.get(queueName); + if (null == newQueue) { + // old queue doesn't exist in the new XML + String configPrefix = newConf.getQueuePrefix( + oldQueue.getQueuePath()); + QueueState newQueueState = null; + try { + newQueueState = QueueState.valueOf( + newConf.get(configPrefix + "state")); + } catch (Exception ex) { + LOG.warn("Not a valid queue state for queue " + + oldQueue.getQueuePath()); + } + if (oldQueue.getState() == QueueState.STOPPED || + newQueueState == QueueState.STOPPED) { + LOG.info("Deleting Queue " + queueName + ", as it is not" + + " present in the modified capacity configuration xml"); + } else{ + throw new IOException(oldQueue.getQueuePath() + " cannot be" + + " deleted from the capacity scheduler configuration, as the" + + " queue is not yet in stopped state. Current State : " + + oldQueue.getState()); + } + } else if (!oldQueue.getQueuePath().equals(newQueue.getQueuePath())) { + //Queue's cannot be moved from one hierarchy to other + throw new IOException( + queueName + " is moved from:" + oldQueue.getQueuePath() + " to:" + + newQueue.getQueuePath() + + " after refresh, which is not allowed."); + } else if (oldQueue instanceof ParentQueue + && !(oldQueue instanceof ManagedParentQueue) + && newQueue instanceof ManagedParentQueue) { + throw new IOException( + "Can not convert parent queue: " + oldQueue.getQueuePath() + + " to auto create enabled parent queue since " + + "it could have other pre-configured queues which is not " + + "supported"); + } else if (oldQueue instanceof ManagedParentQueue + && !(newQueue instanceof ManagedParentQueue)) { + throw new IOException( + "Cannot convert auto create enabled parent queue: " + oldQueue + .getQueuePath() + " to leaf queue. Please check " + + " parent queue's configuration " + + CapacitySchedulerConfiguration + .AUTO_CREATE_CHILD_QUEUE_ENABLED + + " is set to true"); + } else if (oldQueue instanceof LeafQueue + && newQueue instanceof ParentQueue) { + if (oldQueue.getState() == QueueState.STOPPED) { + LOG.info("Converting the leaf queue: " + oldQueue.getQueuePath() + + " to parent queue."); + } else{ + throw new IOException( + "Can not convert the leaf queue: " + oldQueue.getQueuePath() + + " to parent queue since " + + "it is not yet in stopped state. Current State : " + + oldQueue.getState()); + } + } else if (oldQueue instanceof ParentQueue + && newQueue instanceof LeafQueue) { + LOG.info("Converting the parent queue: " + oldQueue.getQueuePath() + + " to leaf queue."); + } + } + } + } +} diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java index d9b3ebd2eda..0bfb81ef0d1 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/CapacitySchedulerQueueManager.java @@ -171,13 +171,13 @@ public void reinitializeQueues(CapacitySchedulerConfiguration newConf) CSQueue newRoot = parseQueue(this.csContext, newConf, null, CapacitySchedulerConfiguration.ROOT, newQueues, queues, NOOP); - // When failing over, if using configuration store, don't validate queue + // When failing over, if using configuration store, don't validate queueR // hierarchy since queues can be removed without being STOPPED. if (!csContext.isConfigurationMutable() || csContext.getRMContext().getHAServiceState() != HAServiceProtocol.HAServiceState.STANDBY) { // Ensure queue hierarchy in the new XML file is proper. - validateQueueHierarchy(queues, newQueues, newConf); + CapacitySchedulerConfigValidator.validateQueueHierarchy(queues, newQueues, newConf); } // Add new queues and delete OldQeueus only after validation. @@ -299,90 +299,6 @@ static CSQueue parseQueue( return queue; } - /** - * Ensure all existing queues are present. Queues cannot be deleted if its not - * in Stopped state, Queue's cannot be moved from one hierarchy to other also. - * Previous child queue could be converted into parent queue if it is in - * STOPPED state. - * - * @param queues existing queues - * @param newQueues new queues - */ - private void validateQueueHierarchy(Map queues, - Map newQueues, CapacitySchedulerConfiguration newConf) - throws IOException { - // check that all static queues are included in the newQueues list - for (Map.Entry e : queues.entrySet()) { - if (!(AbstractAutoCreatedLeafQueue.class.isAssignableFrom(e.getValue() - .getClass()))) { - String queueName = e.getKey(); - CSQueue oldQueue = e.getValue(); - CSQueue newQueue = newQueues.get(queueName); - if (null == newQueue) { - // old queue doesn't exist in the new XML - String configPrefix = newConf.getQueuePrefix( - oldQueue.getQueuePath()); - QueueState newQueueState = null; - try { - newQueueState = QueueState.valueOf( - newConf.get(configPrefix + "state")); - } catch (Exception ex) { - LOG.warn("Not a valid queue state for queue " - + oldQueue.getQueuePath()); - } - if (oldQueue.getState() == QueueState.STOPPED || - newQueueState == QueueState.STOPPED) { - LOG.info("Deleting Queue " + queueName + ", as it is not" - + " present in the modified capacity configuration xml"); - } else{ - throw new IOException(oldQueue.getQueuePath() + " cannot be" - + " deleted from the capacity scheduler configuration, as the" - + " queue is not yet in stopped state. Current State : " - + oldQueue.getState()); - } - } else if (!oldQueue.getQueuePath().equals(newQueue.getQueuePath())) { - //Queue's cannot be moved from one hierarchy to other - throw new IOException( - queueName + " is moved from:" + oldQueue.getQueuePath() + " to:" - + newQueue.getQueuePath() - + " after refresh, which is not allowed."); - } else if (oldQueue instanceof ParentQueue - && !(oldQueue instanceof ManagedParentQueue) - && newQueue instanceof ManagedParentQueue) { - throw new IOException( - "Can not convert parent queue: " + oldQueue.getQueuePath() - + " to auto create enabled parent queue since " - + "it could have other pre-configured queues which is not " - + "supported"); - } else if (oldQueue instanceof ManagedParentQueue - && !(newQueue instanceof ManagedParentQueue)) { - throw new IOException( - "Cannot convert auto create enabled parent queue: " + oldQueue - .getQueuePath() + " to leaf queue. Please check " - + " parent queue's configuration " - + CapacitySchedulerConfiguration - .AUTO_CREATE_CHILD_QUEUE_ENABLED - + " is set to true"); - } else if (oldQueue instanceof LeafQueue - && newQueue instanceof ParentQueue) { - if (oldQueue.getState() == QueueState.STOPPED) { - LOG.info("Converting the leaf queue: " + oldQueue.getQueuePath() - + " to parent queue."); - } else{ - throw new IOException( - "Can not convert the leaf queue: " + oldQueue.getQueuePath() - + " to parent queue since " - + "it is not yet in stopped state. Current State : " - + oldQueue.getState()); - } - } else if (oldQueue instanceof ParentQueue - && newQueue instanceof LeafQueue) { - LOG.info("Converting the parent queue: " + oldQueue.getQueuePath() - + " to leaf queue."); - } - } - } - } /** * Updates to our list of queues: Adds the new queues and deletes the removed diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/conf/MutableCSConfigurationProvider.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/conf/MutableCSConfigurationProvider.java index c8d0a0c6eaa..65ea4a759b9 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/conf/MutableCSConfigurationProvider.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/conf/MutableCSConfigurationProvider.java @@ -131,14 +131,31 @@ public ConfigurationMutationACLPolicy getAclMutationPolicy() { public void logAndApplyMutation(UserGroupInformation user, SchedConfUpdateInfo confUpdate) throws Exception { oldConf = new Configuration(schedConf); - Map kvUpdate = constructKeyValueConfUpdate(confUpdate); + CapacitySchedulerConfiguration proposedConf = + new CapacitySchedulerConfiguration(schedConf, false); + Map kvUpdate + = constructKeyValueConfUpdate(proposedConf, confUpdate); LogMutation log = new LogMutation(kvUpdate, user.getShortUserName()); confStore.logMutation(log); + applyMutation(schedConf, kvUpdate); + } + + public Configuration applyChanges(Configuration oldConfiguration, + SchedConfUpdateInfo confUpdate) throws IOException { + CapacitySchedulerConfiguration proposedConf = + new CapacitySchedulerConfiguration(oldConfiguration, false); + Map kvUpdate + = constructKeyValueConfUpdate(proposedConf, confUpdate); + applyMutation(oldConfiguration, kvUpdate); + return oldConfiguration; + } + + private void applyMutation(Configuration conf, Map kvUpdate) { for (Map.Entry kv : kvUpdate.entrySet()) { if (kv.getValue() == null) { - schedConf.unset(kv.getKey()); + conf.unset(kv.getKey()); } else { - schedConf.set(kv.getKey(), kv.getValue()); + conf.set(kv.getKey(), kv.getValue()); } } } @@ -215,9 +232,9 @@ public void reloadConfigurationFromStore() throws Exception { } private Map constructKeyValueConfUpdate( + CapacitySchedulerConfiguration proposedConf, SchedConfUpdateInfo mutationInfo) throws IOException { - CapacitySchedulerConfiguration proposedConf = - new CapacitySchedulerConfiguration(schedConf, false); + Map confUpdate = new HashMap<>(); for (String queueToRemove : mutationInfo.getRemoveQueueInfo()) { removeQueue(queueToRemove, proposedConf, confUpdate); diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java index b7381038855..b0ff12a68fe 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWSConsts.java @@ -57,6 +57,10 @@ /** Path for {@code RMWebServiceProtocol#dumpSchedulerLogs}. */ public static final String SCHEDULER_LOGS = "/scheduler/logs"; + /** Path for {@code RMWebServiceProtocol#validateCapacitySchedulerConfig}. */ + public static final String SCHEDULER_CONF_VALIDATE + = "/scheduler-conf/validate"; + /** Path for {@code RMWebServiceProtocol#getNodes}. */ public static final String NODES = "/nodes"; @@ -206,6 +210,7 @@ public static final String TIME = "time"; public static final String STATES = "states"; public static final String NODEID = "nodeId"; + public static final String RETURNCONF = "returnConf"; public static final String STATE = "state"; public static final String FINAL_STATUS = "finalStatus"; public static final String USER = "user"; diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java index e63dc068d17..0360db56a04 100644 --- a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java @@ -31,6 +31,7 @@ import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -148,6 +149,9 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CSQueue; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfigValidator; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.conf.MutableCSConfigurationProvider; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.common.fica.FiCaSchedulerNode; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler; import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fifo.FifoScheduler; @@ -2617,6 +2621,53 @@ public Response formatSchedulerConfiguration(@Context HttpServletRequest hsr) } } + @POST + @Path(RMWSConsts.SCHEDULER_CONF_VALIDATE) + @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8, + MediaType.APPLICATION_XML + "; " + JettyUtils.UTF_8 }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public synchronized Response validateAndGetSchedulerConfiguration( + SchedConfUpdateInfo mutationInfo, + @Context HttpServletRequest hsr) { + initForReadableEndpoints(); + ResourceScheduler scheduler = rm.getResourceScheduler(); + if (scheduler instanceof MutableConfScheduler && ((MutableConfScheduler) + scheduler).isConfigurationMutable()) { + try { + Configuration config = new Configuration(false); + rm.getRMContext().getRMAdminService().getConfiguration(config, + YarnConfiguration.CS_CONFIGURATION_FILE); + MutableCSConfigurationProvider provider + = new MutableCSConfigurationProvider(null); + + CapacitySchedulerConfiguration capacitySchedulerConfig = + new CapacitySchedulerConfiguration(config, false); + Configuration newConfig = provider.applyChanges(capacitySchedulerConfig, + mutationInfo); + + CapacitySchedulerConfigValidator.validateCSConfiguration(newConfig, rm.getRMContext()); + + return Response.status(Status.OK) + .entity(new ConfInfo(newConfig)) + .build(); + + } catch (Exception e) { + String errorMsg = "CS configuration validation failed: " + + e.toString(); + LOG.warn(errorMsg); + return Response.status(Status.BAD_REQUEST) + .build(); + } + } else { + String errorMsg = "Configuration change only supported by " + + "MutableConfScheduler."; + LOG.warn(errorMsg); + return Response.status(Status.BAD_REQUEST) + .entity(errorMsg) + .build(); + } + } + @PUT @Path(RMWSConsts.SCHEDULER_CONF) @Produces({ MediaType.APPLICATION_JSON + "; " + JettyUtils.UTF_8, diff --git a/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerConfigValidator.java b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerConfigValidator.java new file mode 100644 index 00000000000..70e53451341 --- /dev/null +++ b/hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/scheduler/capacity/TestCapacitySchedulerConfigValidator.java @@ -0,0 +1,110 @@ +/** + * 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.hadoop.yarn.server.resourcemanager.scheduler.capacity; + +import org.junit.Test; + +public class TestCapacitySchedulerConfigValidator { + + @Test + public void testValidateCSConfigInvalidMemoryAllocation() { + + } + + @Test + public void testValidateCSConfigInvalidVCores() { + + } + + @Test + public void testValidateCSConfigDuplicatePlacementRules() { + + } + + @Test + public void testValidateCSConfigInvalidQueueHierarchy() { + + } + + @Test + public void testValidateCSConfigInvalidCapacity() { + + } + + @Test + public void testValidateCSConfigStopALeafQueue() { + + } + + /** + * Stop a leaf queue if there are running child queues + */ + @Test + public void testValidateCSConfigStopANonLeafQueueInvalid() { + + } + + @Test + public void testValidateCSConfigStopANonLeafQueue() { + + } + + /** + * Add a leaf queue without modifying the capacity of other leaf queues + * so the total capacity != 100 + */ + @Test + public void testValidateCSConfigAddALeafQueueInvalid() { + + } + + /** + * Add a leaf queue without modifying the capacity of other leaf queues + * and adjust the capacities of other leaf queues, so total capacity = 100 + */ + @Test + public void testValidateCSConfigAddALeafQueueValid() { + + } + + /** + * Delete a running queue + */ + @Test + public void testValidateCSConfigInvalidQueueDeletion() { + + } + + /** + * Delete a queue and not adjust capacities + */ + @Test + public void testValidateCSConfigInvalidQueueDeletion2() { + + } + + /** + * Delete a queue and adjust capacities to have total capacity = 100 + */ + @Test + public void testValidateCSConfigValidQueueDeletion() { + + } + +}