YARN-5949. Add pluggable configuration ACL policy interface and implementation. (Jonathan Hung via wangda)
Change-Id: Ib98e82ff753bede21fcab2e6ca9ec1e7a5a2008f
This commit is contained in:
parent
d8a5136b1f
commit
a4e6253046
|
@ -680,6 +680,9 @@ public class YarnConfiguration extends Configuration {
|
|||
public static final String DEFAULT_CONFIGURATION_STORE =
|
||||
MEMORY_CONFIGURATION_STORE;
|
||||
|
||||
public static final String RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS =
|
||||
YARN_PREFIX + "scheduler.configuration.mutation.acl-policy.class";
|
||||
|
||||
public static final String YARN_AUTHORIZATION_PROVIDER = YARN_PREFIX
|
||||
+ "authorization-provider";
|
||||
private static final List<String> RM_SERVICES_ADDRESS_CONF_KEYS_HTTP =
|
||||
|
|
|
@ -3379,4 +3379,15 @@
|
|||
<value>memory</value>
|
||||
</property>
|
||||
|
||||
<property>
|
||||
<description>
|
||||
The class to use for configuration mutation ACL policy if using a mutable
|
||||
configuration provider. Controls whether a mutation request is allowed.
|
||||
The DefaultConfigurationMutationACLPolicy checks if the requestor is a
|
||||
YARN admin.
|
||||
</description>
|
||||
<name>yarn.scheduler.configuration.mutation.acl-policy.class</name>
|
||||
<value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.DefaultConfigurationMutationACLPolicy</value>
|
||||
</property>
|
||||
|
||||
</configuration>
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
|
||||
/**
|
||||
* Interface for determining whether configuration mutations are allowed.
|
||||
*/
|
||||
public interface ConfigurationMutationACLPolicy {
|
||||
|
||||
/**
|
||||
* Initialize ACL policy with configuration and RMContext.
|
||||
* @param conf Configuration to initialize with.
|
||||
* @param rmContext rmContext
|
||||
*/
|
||||
void init(Configuration conf, RMContext rmContext);
|
||||
|
||||
/**
|
||||
* Check if mutation is allowed.
|
||||
* @param user User issuing the request
|
||||
* @param confUpdate configurations to be updated
|
||||
* @return whether provided mutation is allowed or not
|
||||
*/
|
||||
boolean isMutationAllowed(UserGroupInformation user, QueueConfigsUpdateInfo
|
||||
confUpdate);
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.util.ReflectionUtils;
|
||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||
|
||||
/**
|
||||
* Factory class for creating instances of
|
||||
* {@link ConfigurationMutationACLPolicy}.
|
||||
*/
|
||||
public final class ConfigurationMutationACLPolicyFactory {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(
|
||||
ConfigurationMutationACLPolicyFactory.class);
|
||||
|
||||
private ConfigurationMutationACLPolicyFactory() {
|
||||
// Unused.
|
||||
}
|
||||
|
||||
public static ConfigurationMutationACLPolicy getPolicy(Configuration conf) {
|
||||
Class<? extends ConfigurationMutationACLPolicy> policyClass =
|
||||
conf.getClass(YarnConfiguration.RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS,
|
||||
DefaultConfigurationMutationACLPolicy.class,
|
||||
ConfigurationMutationACLPolicy.class);
|
||||
LOG.info("Using ConfigurationMutationACLPolicy implementation - " +
|
||||
policyClass);
|
||||
return ReflectionUtils.newInstance(policyClass, conf);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.security.YarnAuthorizationProvider;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
|
||||
/**
|
||||
* Default configuration mutation ACL policy. Checks if user is YARN admin.
|
||||
*/
|
||||
public class DefaultConfigurationMutationACLPolicy implements
|
||||
ConfigurationMutationACLPolicy {
|
||||
|
||||
private YarnAuthorizationProvider authorizer;
|
||||
|
||||
@Override
|
||||
public void init(Configuration conf, RMContext rmContext) {
|
||||
authorizer = YarnAuthorizationProvider.getInstance(conf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutationAllowed(UserGroupInformation user,
|
||||
QueueConfigsUpdateInfo confUpdate) {
|
||||
return authorizer.isAdmin(user);
|
||||
}
|
||||
}
|
|
@ -17,10 +17,11 @@
|
|||
*/
|
||||
package org.apache.hadoop.yarn.server.resourcemanager.scheduler;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for a scheduler that supports changing configuration at runtime.
|
||||
|
@ -31,10 +32,22 @@ public interface MutableConfScheduler extends ResourceScheduler {
|
|||
/**
|
||||
* Update the scheduler's configuration.
|
||||
* @param user Caller of this update
|
||||
* @param confUpdate key-value map of the configuration update
|
||||
* @param confUpdate configuration update
|
||||
* @throws IOException if update is invalid
|
||||
*/
|
||||
void updateConfiguration(UserGroupInformation user,
|
||||
Map<String, String> confUpdate) throws IOException;
|
||||
QueueConfigsUpdateInfo confUpdate) throws IOException;
|
||||
|
||||
/**
|
||||
* Get the scheduler configuration.
|
||||
* @return the scheduler configuration
|
||||
*/
|
||||
Configuration getConfiguration();
|
||||
|
||||
/**
|
||||
* Get queue object based on queue name.
|
||||
* @param queueName the queue name
|
||||
* @return the queue object
|
||||
*/
|
||||
Queue getQueue(String queueName);
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
package org.apache.hadoop.yarn.server.resourcemanager.scheduler;
|
||||
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Interface for allowing changing scheduler configurations.
|
||||
|
@ -32,7 +34,7 @@ public interface MutableConfigurationProvider {
|
|||
* @param confUpdate Key-value pairs for configurations to be updated.
|
||||
* @throws IOException if scheduler could not be reinitialized
|
||||
*/
|
||||
void mutateConfiguration(String user, Map<String, String> confUpdate)
|
||||
throws IOException;
|
||||
void mutateConfiguration(UserGroupInformation user, QueueConfigsUpdateInfo
|
||||
confUpdate) throws IOException;
|
||||
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.Placeme
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.placement.SimplePlacementSet;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.security.AppPriorityACLsManager;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.security.RMContainerTokenSecretManager;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
import org.apache.hadoop.yarn.server.utils.Lock;
|
||||
import org.apache.hadoop.yarn.util.resource.DefaultResourceCalculator;
|
||||
import org.apache.hadoop.yarn.util.resource.ResourceCalculator;
|
||||
|
@ -649,6 +650,7 @@ public class CapacityScheduler extends
|
|||
preemptionManager.refreshQueues(null, this.getRootQueue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public CSQueue getQueue(String queueName) {
|
||||
if (queueName == null) {
|
||||
return null;
|
||||
|
@ -2615,10 +2617,10 @@ public class CapacityScheduler extends
|
|||
|
||||
@Override
|
||||
public void updateConfiguration(UserGroupInformation user,
|
||||
Map<String, String> confUpdate) throws IOException {
|
||||
QueueConfigsUpdateInfo confUpdate) throws IOException {
|
||||
if (csConfProvider instanceof MutableConfigurationProvider) {
|
||||
((MutableConfigurationProvider) csConfProvider).mutateConfiguration(
|
||||
user.getShortUserName(), confUpdate);
|
||||
user, confUpdate);
|
||||
} else {
|
||||
throw new UnsupportedOperationException("Configured CS configuration " +
|
||||
"provider does not support updating configuration.");
|
||||
|
|
|
@ -18,14 +18,27 @@
|
|||
|
||||
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.conf;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.AccessControlException;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ConfigurationMutationACLPolicy;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ConfigurationMutationACLPolicyFactory;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.MutableConfigurationProvider;
|
||||
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.CapacitySchedulerConfiguration;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.conf.YarnConfigurationStore.LogMutation;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
|
@ -38,6 +51,7 @@ public class MutableCSConfigurationProvider implements CSConfigurationProvider,
|
|||
|
||||
private Configuration schedConf;
|
||||
private YarnConfigurationStore confStore;
|
||||
private ConfigurationMutationACLPolicy aclMutationPolicy;
|
||||
private RMContext rmContext;
|
||||
private Configuration conf;
|
||||
|
||||
|
@ -68,6 +82,9 @@ public class MutableCSConfigurationProvider implements CSConfigurationProvider,
|
|||
schedConf.set(kv.getKey(), kv.getValue());
|
||||
}
|
||||
confStore.initialize(config, schedConf);
|
||||
this.aclMutationPolicy = ConfigurationMutationACLPolicyFactory
|
||||
.getPolicy(config);
|
||||
aclMutationPolicy.init(config, rmContext);
|
||||
this.conf = config;
|
||||
}
|
||||
|
||||
|
@ -80,12 +97,17 @@ public class MutableCSConfigurationProvider implements CSConfigurationProvider,
|
|||
}
|
||||
|
||||
@Override
|
||||
public void mutateConfiguration(String user,
|
||||
Map<String, String> confUpdate) throws IOException {
|
||||
public void mutateConfiguration(UserGroupInformation user,
|
||||
QueueConfigsUpdateInfo confUpdate) throws IOException {
|
||||
if (!aclMutationPolicy.isMutationAllowed(user, confUpdate)) {
|
||||
throw new AccessControlException("User is not admin of all modified" +
|
||||
" queues.");
|
||||
}
|
||||
Configuration oldConf = new Configuration(schedConf);
|
||||
LogMutation log = new LogMutation(confUpdate, user);
|
||||
Map<String, String> kvUpdate = constructKeyValueConfUpdate(confUpdate);
|
||||
LogMutation log = new LogMutation(kvUpdate, user.getShortUserName());
|
||||
long id = confStore.logMutation(log);
|
||||
for (Map.Entry<String, String> kv : confUpdate.entrySet()) {
|
||||
for (Map.Entry<String, String> kv : kvUpdate.entrySet()) {
|
||||
if (kv.getValue() == null) {
|
||||
schedConf.unset(kv.getKey());
|
||||
} else {
|
||||
|
@ -101,4 +123,125 @@ public class MutableCSConfigurationProvider implements CSConfigurationProvider,
|
|||
}
|
||||
confStore.confirmMutation(id, true);
|
||||
}
|
||||
|
||||
|
||||
private Map<String, String> constructKeyValueConfUpdate(
|
||||
QueueConfigsUpdateInfo mutationInfo) throws IOException {
|
||||
CapacityScheduler cs = (CapacityScheduler) rmContext.getScheduler();
|
||||
CapacitySchedulerConfiguration proposedConf =
|
||||
new CapacitySchedulerConfiguration(cs.getConfiguration(), false);
|
||||
Map<String, String> confUpdate = new HashMap<>();
|
||||
for (String queueToRemove : mutationInfo.getRemoveQueueInfo()) {
|
||||
removeQueue(queueToRemove, proposedConf, confUpdate);
|
||||
}
|
||||
for (QueueConfigInfo addQueueInfo : mutationInfo.getAddQueueInfo()) {
|
||||
addQueue(addQueueInfo, proposedConf, confUpdate);
|
||||
}
|
||||
for (QueueConfigInfo updateQueueInfo : mutationInfo.getUpdateQueueInfo()) {
|
||||
updateQueue(updateQueueInfo, proposedConf, confUpdate);
|
||||
}
|
||||
return confUpdate;
|
||||
}
|
||||
|
||||
private void removeQueue(
|
||||
String queueToRemove, CapacitySchedulerConfiguration proposedConf,
|
||||
Map<String, String> confUpdate) throws IOException {
|
||||
if (queueToRemove == null) {
|
||||
return;
|
||||
} else {
|
||||
CapacityScheduler cs = (CapacityScheduler) rmContext.getScheduler();
|
||||
String queueName = queueToRemove.substring(
|
||||
queueToRemove.lastIndexOf('.') + 1);
|
||||
CSQueue queue = cs.getQueue(queueName);
|
||||
if (queue == null ||
|
||||
!queue.getQueuePath().equals(queueToRemove)) {
|
||||
throw new IOException("Queue " + queueToRemove + " not found");
|
||||
} else if (queueToRemove.lastIndexOf('.') == -1) {
|
||||
throw new IOException("Can't remove queue " + queueToRemove);
|
||||
}
|
||||
String parentQueuePath = queueToRemove.substring(0, queueToRemove
|
||||
.lastIndexOf('.'));
|
||||
String[] siblingQueues = proposedConf.getQueues(parentQueuePath);
|
||||
List<String> newSiblingQueues = new ArrayList<>();
|
||||
for (String siblingQueue : siblingQueues) {
|
||||
if (!siblingQueue.equals(queueName)) {
|
||||
newSiblingQueues.add(siblingQueue);
|
||||
}
|
||||
}
|
||||
proposedConf.setQueues(parentQueuePath, newSiblingQueues
|
||||
.toArray(new String[0]));
|
||||
String queuesConfig = CapacitySchedulerConfiguration.PREFIX
|
||||
+ parentQueuePath + CapacitySchedulerConfiguration.DOT
|
||||
+ CapacitySchedulerConfiguration.QUEUES;
|
||||
if (newSiblingQueues.size() == 0) {
|
||||
confUpdate.put(queuesConfig, null);
|
||||
} else {
|
||||
confUpdate.put(queuesConfig, Joiner.on(',').join(newSiblingQueues));
|
||||
}
|
||||
for (Map.Entry<String, String> confRemove : proposedConf.getValByRegex(
|
||||
".*" + queueToRemove.replaceAll("\\.", "\\.") + "\\..*")
|
||||
.entrySet()) {
|
||||
proposedConf.unset(confRemove.getKey());
|
||||
confUpdate.put(confRemove.getKey(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addQueue(
|
||||
QueueConfigInfo addInfo, CapacitySchedulerConfiguration proposedConf,
|
||||
Map<String, String> confUpdate) throws IOException {
|
||||
if (addInfo == null) {
|
||||
return;
|
||||
} else {
|
||||
CapacityScheduler cs = (CapacityScheduler) rmContext.getScheduler();
|
||||
String queuePath = addInfo.getQueue();
|
||||
String queueName = queuePath.substring(queuePath.lastIndexOf('.') + 1);
|
||||
if (cs.getQueue(queueName) != null) {
|
||||
throw new IOException("Can't add existing queue " + queuePath);
|
||||
} else if (queuePath.lastIndexOf('.') == -1) {
|
||||
throw new IOException("Can't add invalid queue " + queuePath);
|
||||
}
|
||||
String parentQueue = queuePath.substring(0, queuePath.lastIndexOf('.'));
|
||||
String[] siblings = proposedConf.getQueues(parentQueue);
|
||||
List<String> siblingQueues = siblings == null ? new ArrayList<>() :
|
||||
new ArrayList<>(Arrays.<String>asList(siblings));
|
||||
siblingQueues.add(queuePath.substring(queuePath.lastIndexOf('.') + 1));
|
||||
proposedConf.setQueues(parentQueue,
|
||||
siblingQueues.toArray(new String[0]));
|
||||
confUpdate.put(CapacitySchedulerConfiguration.PREFIX
|
||||
+ parentQueue + CapacitySchedulerConfiguration.DOT
|
||||
+ CapacitySchedulerConfiguration.QUEUES,
|
||||
Joiner.on(',').join(siblingQueues));
|
||||
String keyPrefix = CapacitySchedulerConfiguration.PREFIX
|
||||
+ queuePath + CapacitySchedulerConfiguration.DOT;
|
||||
for (Map.Entry<String, String> kv : addInfo.getParams().entrySet()) {
|
||||
if (kv.getValue() == null) {
|
||||
proposedConf.unset(keyPrefix + kv.getKey());
|
||||
} else {
|
||||
proposedConf.set(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
confUpdate.put(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateQueue(QueueConfigInfo updateInfo,
|
||||
CapacitySchedulerConfiguration proposedConf,
|
||||
Map<String, String> confUpdate) {
|
||||
if (updateInfo == null) {
|
||||
return;
|
||||
} else {
|
||||
String queuePath = updateInfo.getQueue();
|
||||
String keyPrefix = CapacitySchedulerConfiguration.PREFIX
|
||||
+ queuePath + CapacitySchedulerConfiguration.DOT;
|
||||
for (Map.Entry<String, String> kv : updateInfo.getParams().entrySet()) {
|
||||
if (kv.getValue() == null) {
|
||||
proposedConf.unset(keyPrefix + kv.getKey());
|
||||
} else {
|
||||
proposedConf.set(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
confUpdate.put(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* 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.conf;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.api.records.QueueACL;
|
||||
import org.apache.hadoop.yarn.api.records.QueueInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ConfigurationMutationACLPolicy;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.MutableConfScheduler;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.Queue;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A configuration mutation ACL policy which checks that user has admin
|
||||
* privileges on all queues they are changing.
|
||||
*/
|
||||
public class QueueAdminConfigurationMutationACLPolicy implements
|
||||
ConfigurationMutationACLPolicy {
|
||||
|
||||
private RMContext rmContext;
|
||||
|
||||
@Override
|
||||
public void init(Configuration conf, RMContext context) {
|
||||
this.rmContext = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutationAllowed(UserGroupInformation user,
|
||||
QueueConfigsUpdateInfo confUpdate) {
|
||||
Set<String> queues = new HashSet<>();
|
||||
for (QueueConfigInfo addQueueInfo : confUpdate.getAddQueueInfo()) {
|
||||
queues.add(addQueueInfo.getQueue());
|
||||
}
|
||||
for (String removeQueue : confUpdate.getRemoveQueueInfo()) {
|
||||
queues.add(removeQueue);
|
||||
}
|
||||
for (QueueConfigInfo updateQueueInfo : confUpdate.getUpdateQueueInfo()) {
|
||||
queues.add(updateQueueInfo.getQueue());
|
||||
}
|
||||
for (String queuePath : queues) {
|
||||
String queueName = queuePath.lastIndexOf('.') != -1 ?
|
||||
queuePath.substring(queuePath.lastIndexOf('.') + 1) : queuePath;
|
||||
QueueInfo queueInfo = null;
|
||||
try {
|
||||
queueInfo = rmContext.getScheduler()
|
||||
.getQueueInfo(queueName, false, false);
|
||||
} catch (IOException e) {
|
||||
// Queue is not found, do nothing.
|
||||
}
|
||||
String parentPath = queuePath;
|
||||
// TODO: handle global config change.
|
||||
while (queueInfo == null) {
|
||||
// We are adding a queue (whose parent we are possibly also adding).
|
||||
// Check ACL of lowest parent queue which already exists.
|
||||
parentPath = parentPath.substring(0, parentPath.lastIndexOf('.'));
|
||||
String parentName = parentPath.lastIndexOf('.') != -1 ?
|
||||
parentPath.substring(parentPath.lastIndexOf('.') + 1) : parentPath;
|
||||
try {
|
||||
queueInfo = rmContext.getScheduler()
|
||||
.getQueueInfo(parentName, false, false);
|
||||
} catch (IOException e) {
|
||||
// Queue is not found, do nothing.
|
||||
}
|
||||
}
|
||||
Queue queue = ((MutableConfScheduler) rmContext.getScheduler())
|
||||
.getQueue(queueInfo.getQueueName());
|
||||
if (queue != null && !queue.hasAccess(QueueACL.ADMINISTER_QUEUE, user)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -142,7 +142,6 @@ import org.apache.hadoop.yarn.server.resourcemanager.scheduler.YarnScheduler;
|
|||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.activities.ActivitiesManager;
|
||||
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.CapacitySchedulerConfiguration;
|
||||
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;
|
||||
|
@ -2484,10 +2483,8 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
|
|||
callerUGI.doAs(new PrivilegedExceptionAction<Void>() {
|
||||
@Override
|
||||
public Void run() throws IOException, YarnException {
|
||||
Map<String, String> confUpdate =
|
||||
constructKeyValueConfUpdate(mutationInfo);
|
||||
((CapacityScheduler) scheduler).updateConfiguration(callerUGI,
|
||||
confUpdate);
|
||||
((MutableConfScheduler) scheduler).updateConfiguration(callerUGI,
|
||||
mutationInfo);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
@ -2499,129 +2496,9 @@ public class RMWebServices extends WebServices implements RMWebServiceProtocol {
|
|||
"successfully applied.").build();
|
||||
} else {
|
||||
return Response.status(Status.BAD_REQUEST)
|
||||
.entity("Configuration change only supported by CapacityScheduler.")
|
||||
.entity("Configuration change only supported by " +
|
||||
"MutableConfScheduler.")
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, String> constructKeyValueConfUpdate(
|
||||
QueueConfigsUpdateInfo mutationInfo) throws IOException {
|
||||
CapacitySchedulerConfiguration currentConf =
|
||||
((CapacityScheduler) rm.getResourceScheduler()).getConfiguration();
|
||||
CapacitySchedulerConfiguration proposedConf =
|
||||
new CapacitySchedulerConfiguration(currentConf, false);
|
||||
Map<String, String> confUpdate = new HashMap<>();
|
||||
for (String queueToRemove : mutationInfo.getRemoveQueueInfo()) {
|
||||
removeQueue(queueToRemove, proposedConf, confUpdate);
|
||||
}
|
||||
for (QueueConfigInfo addQueueInfo : mutationInfo.getAddQueueInfo()) {
|
||||
addQueue(addQueueInfo, proposedConf, confUpdate);
|
||||
}
|
||||
for (QueueConfigInfo updateQueueInfo : mutationInfo.getUpdateQueueInfo()) {
|
||||
updateQueue(updateQueueInfo, proposedConf, confUpdate);
|
||||
}
|
||||
return confUpdate;
|
||||
}
|
||||
|
||||
private void removeQueue(
|
||||
String queueToRemove, CapacitySchedulerConfiguration proposedConf,
|
||||
Map<String, String> confUpdate) throws IOException {
|
||||
if (queueToRemove == null) {
|
||||
return;
|
||||
} else {
|
||||
CapacityScheduler cs = (CapacityScheduler) rm.getResourceScheduler();
|
||||
String queueName = queueToRemove.substring(
|
||||
queueToRemove.lastIndexOf('.') + 1);
|
||||
CSQueue queue = cs.getQueue(queueName);
|
||||
if (queue == null ||
|
||||
!queue.getQueuePath().equals(queueToRemove)) {
|
||||
throw new IOException("Queue " + queueToRemove + " not found");
|
||||
} else if (queueToRemove.lastIndexOf('.') == -1) {
|
||||
throw new IOException("Can't remove queue " + queueToRemove);
|
||||
}
|
||||
String parentQueuePath = queueToRemove.substring(0, queueToRemove
|
||||
.lastIndexOf('.'));
|
||||
String[] siblingQueues = proposedConf.getQueues(parentQueuePath);
|
||||
List<String> newSiblingQueues = new ArrayList<>();
|
||||
for (String siblingQueue : siblingQueues) {
|
||||
if (!siblingQueue.equals(queueName)) {
|
||||
newSiblingQueues.add(siblingQueue);
|
||||
}
|
||||
}
|
||||
proposedConf.setQueues(parentQueuePath, newSiblingQueues
|
||||
.toArray(new String[0]));
|
||||
String queuesConfig = CapacitySchedulerConfiguration.PREFIX +
|
||||
parentQueuePath + CapacitySchedulerConfiguration.DOT +
|
||||
CapacitySchedulerConfiguration.QUEUES;
|
||||
if (newSiblingQueues.size() == 0) {
|
||||
confUpdate.put(queuesConfig, null);
|
||||
} else {
|
||||
confUpdate.put(queuesConfig, Joiner.on(',').join(newSiblingQueues));
|
||||
}
|
||||
for (Map.Entry<String, String> confRemove : proposedConf.getValByRegex(
|
||||
".*" + queueToRemove.replaceAll("\\.", "\\.") + "\\..*")
|
||||
.entrySet()) {
|
||||
proposedConf.unset(confRemove.getKey());
|
||||
confUpdate.put(confRemove.getKey(), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addQueue(
|
||||
QueueConfigInfo addInfo, CapacitySchedulerConfiguration proposedConf,
|
||||
Map<String, String> confUpdate) throws IOException {
|
||||
if (addInfo == null) {
|
||||
return;
|
||||
} else {
|
||||
CapacityScheduler cs = (CapacityScheduler) rm.getResourceScheduler();
|
||||
String queuePath = addInfo.getQueue();
|
||||
String queueName = queuePath.substring(queuePath.lastIndexOf('.') + 1);
|
||||
if (cs.getQueue(queueName) != null) {
|
||||
throw new IOException("Can't add existing queue " + queuePath);
|
||||
} else if (queuePath.lastIndexOf('.') == -1) {
|
||||
throw new IOException("Can't add invalid queue " + queuePath);
|
||||
}
|
||||
String parentQueue = queuePath.substring(0, queuePath.lastIndexOf('.'));
|
||||
String[] siblings = proposedConf.getQueues(parentQueue);
|
||||
List<String> siblingQueues = siblings == null ? new ArrayList<>() :
|
||||
new ArrayList<>(Arrays.<String>asList(siblings));
|
||||
siblingQueues.add(queuePath.substring(queuePath.lastIndexOf('.') + 1));
|
||||
proposedConf.setQueues(parentQueue,
|
||||
siblingQueues.toArray(new String[0]));
|
||||
confUpdate.put(CapacitySchedulerConfiguration.PREFIX +
|
||||
parentQueue + CapacitySchedulerConfiguration.DOT +
|
||||
CapacitySchedulerConfiguration.QUEUES,
|
||||
Joiner.on(',').join(siblingQueues));
|
||||
String keyPrefix = CapacitySchedulerConfiguration.PREFIX +
|
||||
queuePath + CapacitySchedulerConfiguration.DOT;
|
||||
for (Map.Entry<String, String> kv : addInfo.getParams().entrySet()) {
|
||||
if (kv.getValue() == null) {
|
||||
proposedConf.unset(keyPrefix + kv.getKey());
|
||||
} else {
|
||||
proposedConf.set(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
confUpdate.put(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateQueue(QueueConfigInfo updateInfo,
|
||||
CapacitySchedulerConfiguration proposedConf,
|
||||
Map<String, String> confUpdate) {
|
||||
if (updateInfo == null) {
|
||||
return;
|
||||
} else {
|
||||
String queuePath = updateInfo.getQueue();
|
||||
String keyPrefix = CapacitySchedulerConfiguration.PREFIX +
|
||||
queuePath + CapacitySchedulerConfiguration.DOT;
|
||||
for (Map.Entry<String, String> kv : updateInfo.getParams().entrySet()) {
|
||||
if (kv.getValue() == null) {
|
||||
proposedConf.unset(keyPrefix + kv.getKey());
|
||||
} else {
|
||||
proposedConf.set(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
confUpdate.put(keyPrefix + kv.getKey(), kv.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,154 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.api.records.QueueACL;
|
||||
import org.apache.hadoop.yarn.api.records.QueueInfo;
|
||||
import org.apache.hadoop.yarn.conf.YarnConfiguration;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.conf.QueueAdminConfigurationMutationACLPolicy;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class TestConfigurationMutationACLPolicies {
|
||||
|
||||
private ConfigurationMutationACLPolicy policy;
|
||||
private RMContext rmContext;
|
||||
private MutableConfScheduler scheduler;
|
||||
|
||||
private static final UserGroupInformation GOOD_USER = UserGroupInformation
|
||||
.createUserForTesting("goodUser", new String[] {});
|
||||
private static final UserGroupInformation BAD_USER = UserGroupInformation
|
||||
.createUserForTesting("badUser", new String[] {});
|
||||
private static final Map<String, String> EMPTY_MAP =
|
||||
Collections.<String, String>emptyMap();
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
rmContext = mock(RMContext.class);
|
||||
scheduler = mock(MutableConfScheduler.class);
|
||||
when(rmContext.getScheduler()).thenReturn(scheduler);
|
||||
mockQueue("a", scheduler);
|
||||
mockQueue("b", scheduler);
|
||||
mockQueue("b1", scheduler);
|
||||
}
|
||||
|
||||
private void mockQueue(String queueName, MutableConfScheduler scheduler)
|
||||
throws IOException {
|
||||
QueueInfo queueInfo = QueueInfo.newInstance(queueName, 0, 0, 0, null, null,
|
||||
null, null, null, null, false);
|
||||
when(scheduler.getQueueInfo(eq(queueName), anyBoolean(), anyBoolean()))
|
||||
.thenReturn(queueInfo);
|
||||
Queue queue = mock(Queue.class);
|
||||
when(queue.hasAccess(eq(QueueACL.ADMINISTER_QUEUE), eq(GOOD_USER)))
|
||||
.thenReturn(true);
|
||||
when(queue.hasAccess(eq(QueueACL.ADMINISTER_QUEUE), eq(BAD_USER)))
|
||||
.thenReturn(false);
|
||||
when(scheduler.getQueue(eq(queueName))).thenReturn(queue);
|
||||
}
|
||||
@Test
|
||||
public void testDefaultPolicy() {
|
||||
Configuration conf = new Configuration();
|
||||
conf.set(YarnConfiguration.YARN_ADMIN_ACL, GOOD_USER.getShortUserName());
|
||||
conf.setClass(YarnConfiguration.RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS,
|
||||
DefaultConfigurationMutationACLPolicy.class,
|
||||
ConfigurationMutationACLPolicy.class);
|
||||
policy = ConfigurationMutationACLPolicyFactory.getPolicy(conf);
|
||||
policy.init(conf, rmContext);
|
||||
assertTrue(policy.isMutationAllowed(GOOD_USER, null));
|
||||
assertFalse(policy.isMutationAllowed(BAD_USER, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueueAdminBasedPolicy() {
|
||||
Configuration conf = new Configuration();
|
||||
conf.setClass(YarnConfiguration.RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS,
|
||||
QueueAdminConfigurationMutationACLPolicy.class,
|
||||
ConfigurationMutationACLPolicy.class);
|
||||
policy = ConfigurationMutationACLPolicyFactory.getPolicy(conf);
|
||||
policy.init(conf, rmContext);
|
||||
QueueConfigsUpdateInfo updateInfo = new QueueConfigsUpdateInfo();
|
||||
QueueConfigInfo configInfo = new QueueConfigInfo("root.a", EMPTY_MAP);
|
||||
updateInfo.getUpdateQueueInfo().add(configInfo);
|
||||
assertTrue(policy.isMutationAllowed(GOOD_USER, updateInfo));
|
||||
assertFalse(policy.isMutationAllowed(BAD_USER, updateInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueueAdminPolicyAddQueue() {
|
||||
Configuration conf = new Configuration();
|
||||
conf.setClass(YarnConfiguration.RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS,
|
||||
QueueAdminConfigurationMutationACLPolicy.class,
|
||||
ConfigurationMutationACLPolicy.class);
|
||||
policy = ConfigurationMutationACLPolicyFactory.getPolicy(conf);
|
||||
policy.init(conf, rmContext);
|
||||
// Add root.b.b1. Should check ACL of root.b queue.
|
||||
QueueConfigsUpdateInfo updateInfo = new QueueConfigsUpdateInfo();
|
||||
QueueConfigInfo configInfo = new QueueConfigInfo("root.b.b2", EMPTY_MAP);
|
||||
updateInfo.getAddQueueInfo().add(configInfo);
|
||||
assertTrue(policy.isMutationAllowed(GOOD_USER, updateInfo));
|
||||
assertFalse(policy.isMutationAllowed(BAD_USER, updateInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueueAdminPolicyAddNestedQueue() {
|
||||
Configuration conf = new Configuration();
|
||||
conf.setClass(YarnConfiguration.RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS,
|
||||
QueueAdminConfigurationMutationACLPolicy.class,
|
||||
ConfigurationMutationACLPolicy.class);
|
||||
policy = ConfigurationMutationACLPolicyFactory.getPolicy(conf);
|
||||
policy.init(conf, rmContext);
|
||||
// Add root.b.b1.b11. Should check ACL of root.b queue.
|
||||
QueueConfigsUpdateInfo updateInfo = new QueueConfigsUpdateInfo();
|
||||
QueueConfigInfo configInfo = new QueueConfigInfo("root.b.b2.b21", EMPTY_MAP);
|
||||
updateInfo.getAddQueueInfo().add(configInfo);
|
||||
assertTrue(policy.isMutationAllowed(GOOD_USER, updateInfo));
|
||||
assertFalse(policy.isMutationAllowed(BAD_USER, updateInfo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQueueAdminPolicyRemoveQueue() {
|
||||
Configuration conf = new Configuration();
|
||||
conf.setClass(YarnConfiguration.RM_SCHEDULER_MUTATION_ACL_POLICY_CLASS,
|
||||
QueueAdminConfigurationMutationACLPolicy.class,
|
||||
ConfigurationMutationACLPolicy.class);
|
||||
policy = ConfigurationMutationACLPolicyFactory.getPolicy(conf);
|
||||
policy.init(conf, rmContext);
|
||||
// Remove root.b.b1.
|
||||
QueueConfigsUpdateInfo updateInfo = new QueueConfigsUpdateInfo();
|
||||
updateInfo.getRemoveQueueInfo().add("root.b.b1");
|
||||
assertTrue(policy.isMutationAllowed(GOOD_USER, updateInfo));
|
||||
assertFalse(policy.isMutationAllowed(BAD_USER, updateInfo));
|
||||
}
|
||||
}
|
|
@ -19,8 +19,12 @@
|
|||
package org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.conf;
|
||||
|
||||
import org.apache.hadoop.conf.Configuration;
|
||||
import org.apache.hadoop.security.UserGroupInformation;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigInfo;
|
||||
import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.QueueConfigsUpdateInfo;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -43,22 +47,34 @@ public class TestMutableCSConfigurationProvider {
|
|||
|
||||
private MutableCSConfigurationProvider confProvider;
|
||||
private RMContext rmContext;
|
||||
private Map<String, String> goodUpdate;
|
||||
private Map<String, String> badUpdate;
|
||||
private QueueConfigsUpdateInfo goodUpdate;
|
||||
private QueueConfigsUpdateInfo badUpdate;
|
||||
private CapacityScheduler cs;
|
||||
|
||||
private static final String TEST_USER = "testUser";
|
||||
private static final UserGroupInformation TEST_USER = UserGroupInformation
|
||||
.createUserForTesting("testUser", new String[] {});
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
cs = mock(CapacityScheduler.class);
|
||||
rmContext = mock(RMContext.class);
|
||||
when(rmContext.getScheduler()).thenReturn(cs);
|
||||
when(cs.getConfiguration()).thenReturn(
|
||||
new CapacitySchedulerConfiguration());
|
||||
confProvider = new MutableCSConfigurationProvider(rmContext);
|
||||
goodUpdate = new HashMap<>();
|
||||
goodUpdate.put("goodKey", "goodVal");
|
||||
badUpdate = new HashMap<>();
|
||||
badUpdate.put("badKey", "badVal");
|
||||
goodUpdate = new QueueConfigsUpdateInfo();
|
||||
Map<String, String> goodUpdateMap = new HashMap<>();
|
||||
goodUpdateMap.put("goodKey", "goodVal");
|
||||
QueueConfigInfo goodUpdateInfo = new
|
||||
QueueConfigInfo("root.a", goodUpdateMap);
|
||||
goodUpdate.getUpdateQueueInfo().add(goodUpdateInfo);
|
||||
|
||||
badUpdate = new QueueConfigsUpdateInfo();
|
||||
Map<String, String> badUpdateMap = new HashMap<>();
|
||||
badUpdateMap.put("badKey", "badVal");
|
||||
QueueConfigInfo badUpdateInfo = new
|
||||
QueueConfigInfo("root.a", badUpdateMap);
|
||||
badUpdate.getUpdateQueueInfo().add(badUpdateInfo);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -66,15 +82,16 @@ public class TestMutableCSConfigurationProvider {
|
|||
Configuration conf = new Configuration();
|
||||
confProvider.init(conf);
|
||||
assertNull(confProvider.loadConfiguration(conf)
|
||||
.get("goodKey"));
|
||||
.get("yarn.scheduler.capacity.root.a.goodKey"));
|
||||
|
||||
doNothing().when(cs).reinitialize(any(Configuration.class),
|
||||
any(RMContext.class));
|
||||
confProvider.mutateConfiguration(TEST_USER, goodUpdate);
|
||||
assertEquals("goodVal", confProvider.loadConfiguration(conf)
|
||||
.get("goodKey"));
|
||||
.get("yarn.scheduler.capacity.root.a.goodKey"));
|
||||
|
||||
assertNull(confProvider.loadConfiguration(conf).get("badKey"));
|
||||
assertNull(confProvider.loadConfiguration(conf).get(
|
||||
"yarn.scheduler.capacity.root.a.badKey"));
|
||||
doThrow(new IOException()).when(cs).reinitialize(any(Configuration.class),
|
||||
any(RMContext.class));
|
||||
try {
|
||||
|
@ -82,6 +99,7 @@ public class TestMutableCSConfigurationProvider {
|
|||
} catch (IOException e) {
|
||||
// Expected exception.
|
||||
}
|
||||
assertNull(confProvider.loadConfiguration(conf).get("badKey"));
|
||||
assertNull(confProvider.loadConfiguration(conf).get(
|
||||
"yarn.scheduler.capacity.root.a.badKey"));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue