SLIDER-1026 AM can't make YarnClient calls on a secure cluster
Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/46bd87fc Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/46bd87fc Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/46bd87fc Branch: refs/heads/develop Commit: 46bd87fc8765722f84f50caf4228e45a40587668 Parents: 9cb9661 Author: Steve Loughran <ste...@apache.org> Authored: Tue Dec 15 16:04:33 2015 +0000 Committer: Steve Loughran <ste...@apache.org> Committed: Tue Dec 15 16:04:33 2015 +0000 ---------------------------------------------------------------------- .../server/appmaster/SliderAppMaster.java | 96 +++++++++++++++++--- 1 file changed, 81 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/46bd87fc/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java index 27f6fca..d8fb56e 100644 --- a/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java +++ b/slider-core/src/main/java/org/apache/slider/server/appmaster/SliderAppMaster.java @@ -44,6 +44,7 @@ import org.apache.hadoop.security.UserGroupInformation; import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.service.Service; +import org.apache.hadoop.service.ServiceOperations; import org.apache.hadoop.service.ServiceStateChangeListener; import org.apache.hadoop.yarn.api.ApplicationConstants; import org.apache.hadoop.yarn.api.protocolrecords.RegisterApplicationMasterResponse; @@ -179,6 +180,7 @@ import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.nio.ByteBuffer; +import java.security.PrivilegedExceptionAction; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -414,7 +416,6 @@ public class SliderAppMaster extends AbstractSliderLaunchedService */ private boolean securityEnabled; private ContentCache contentCache; - private SliderYarnClientImpl yarnClient; /** * resource limits @@ -694,8 +695,6 @@ public class SliderAppMaster extends AbstractSliderLaunchedService serviceConf.set(YarnConfiguration.RM_ADDRESS, String.format("%s:%d", rmSchedulerAddress.getHostString(), clientRpcAddress.getPort() )); } - initAndAddService(yarnClient = new SliderYarnClientImpl()); - yarnClient.start(); /* * Extract the container ID. This is then @@ -715,9 +714,6 @@ public class SliderAppMaster extends AbstractSliderLaunchedService Map<String, String> envVars; List<Container> liveContainers; - List<NodeReport> nodeReports = yarnClient.getNodeReports(NodeState.RUNNING); - log.info("Yarn node report count: {}", nodeReports.size()); - /* * It is critical this section is synchronized, to stop async AM events * arriving while registering a restarting AM. @@ -847,15 +843,31 @@ public class SliderAppMaster extends AbstractSliderLaunchedService } } - // look up the application itself -this is needed to get the proxied - // URL of the AM, for registering endpoints. - // this call must be made after the AM has registered itself, obviously - ApplicationAttemptReport report = yarnClient.getApplicationAttemptReport( - appAttemptID); - appMasterProxiedUrl = report.getTrackingUrl(); - if (SliderUtils.isUnset(appMasterProxiedUrl)) { - log.warn("Proxied URL is not set in application report"); - appMasterProxiedUrl = appMasterTrackingUrl; + // YARN client. + // Important: this is only valid at startup, and must be executed within + // the right UGI context. Use with care. + SliderYarnClientImpl yarnClient = null; + List<NodeReport> nodeReports; + try { + yarnClient = new SliderYarnClientImpl(); + yarnClient.init(getConfig()); + yarnClient.start(); + nodeReports = getNodeReports(yarnClient); + log.info("Yarn node report count: {}", nodeReports.size()); + // look up the application itself -this is needed to get the proxied + // URL of the AM, for registering endpoints. + // this call must be made after the AM has registered itself, obviously + ApplicationAttemptReport report = getApplicationAttemptReport(yarnClient); + appMasterProxiedUrl = report.getTrackingUrl(); + if (SliderUtils.isUnset(appMasterProxiedUrl)) { + log.warn("Proxied URL is not set in application report"); + appMasterProxiedUrl = appMasterTrackingUrl; + } + } finally { + // at this point yarnClient is no longer needed. + // stop it immediately + ServiceOperations.stop(yarnClient); + yarnClient = null; } // extract container list @@ -1011,6 +1023,60 @@ public class SliderAppMaster extends AbstractSliderLaunchedService } /** + * Get the YARN application Attempt report as the logged in user + * @param yarnClient client to the RM + * @return the appication report + * @throws YarnException + * @throws IOException + * @throws InterruptedException + */ + private ApplicationAttemptReport getApplicationAttemptReport( + final SliderYarnClientImpl yarnClient) + throws YarnException, IOException, InterruptedException { + Preconditions.checkNotNull(yarnClient, "Null Yarn client"); + ApplicationAttemptReport report; + if (securityEnabled) { + UserGroupInformation ugi = UserGroupInformation.getLoginUser(); + report = ugi.doAs(new PrivilegedExceptionAction<ApplicationAttemptReport>() { + @Override + public ApplicationAttemptReport run() throws Exception { + return yarnClient.getApplicationAttemptReport(appAttemptID); + } + }); + } else { + report = yarnClient.getApplicationAttemptReport(appAttemptID); + } + return report; + } + + /** + * List the node reports: uses {@link #yarnClient} as the login user + * @param yarnClient client to the RM + * @return the node reports + * @throws IOException + * @throws YarnException + * @throws InterruptedException + */ + private List<NodeReport> getNodeReports(final SliderYarnClientImpl yarnClient) + throws IOException, YarnException, InterruptedException { + Preconditions.checkNotNull(yarnClient, "Null Yarn client"); + List<NodeReport> nodeReports; + if (securityEnabled) { + nodeReports = UserGroupInformation.getLoginUser().doAs( + new PrivilegedExceptionAction<List<NodeReport>>() { + @Override + public List<NodeReport> run() throws Exception { + return yarnClient.getNodeReports(NodeState.RUNNING); + } + }); + } else { + nodeReports = yarnClient.getNodeReports(NodeState.RUNNING); + } + log.info("Yarn node report count: {}", nodeReports.size()); + return nodeReports; + } + + /** * Deploy the web application. * <p> * Creates and starts the web application, and adds a