diff --git a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java index e50ff997a909e4fe1a91dd6afdf96dd2fcae0e5e..aa1d449e690a3958a5efa090f789dfc19f925c75 100644 --- a/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java +++ b/common/src/java/org/apache/hadoop/hive/conf/HiveConf.java @@ -4184,7 +4184,8 @@ private static void populateLlapDaemonVarsSet(Set llapDaemonVarsSetLocal LLAP_KERBEROS_PRINCIPAL(HIVE_LLAP_DAEMON_SERVICE_PRINCIPAL_NAME, "", "The name of the LLAP daemon's service principal."), LLAP_KERBEROS_KEYTAB_FILE("hive.llap.daemon.keytab.file", "", - "The path to the Kerberos Keytab file containing the LLAP daemon's service principal."), + "The path to the Kerberos Keytab file on local FS containing the LLAP daemon's service " + + "principal."), LLAP_WEBUI_SPNEGO_KEYTAB_FILE("hive.llap.webui.spnego.keytab", "", "The path to the Kerberos Keytab file containing the LLAP WebUI SPNEGO principal.\n" + "Typical value would look like /etc/security/keytabs/spnego.service.keytab."), @@ -4347,7 +4348,11 @@ private static void populateLlapDaemonVarsSet(Set llapDaemonVarsSetLocal LLAP_TASK_SCHEDULER_AM_REGISTRY_PRINCIPAL("hive.llap.task.scheduler.am.registry.principal", "", "The name of the principal used to access ZK AM registry securely."), LLAP_TASK_SCHEDULER_AM_REGISTRY_KEYTAB_FILE("hive.llap.task.scheduler.am.registry.keytab.file", "", - "The path to the Kerberos keytab file used to access ZK AM registry securely."), + "The path to the Kerberos keytab file on local FS used to access ZK AM registry securely."), + LLAP_USE_HS2_KEYTAB_FOR_AM_REGISTRY_KEYTAB("hive.llap.use.hs2.keytab.for.am.registry.keytab", + false, "Whether or not to reuse keytab of HS2 on Tez AM side for ZK access too." + + "Such keytab propagation will only happen if this is set to true, and the value is left " + + "blank for LLAP_TASK_SCHEDULER_AM_REGISTRY_KEYTAB_FILE on a the secure cluster."), LLAP_TASK_SCHEDULER_NODE_REENABLE_MIN_TIMEOUT_MS( "hive.llap.task.scheduler.node.reenable.min.timeout.ms", "200ms", new TimeValidator(TimeUnit.MILLISECONDS), diff --git a/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java b/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java index 532310228232cfd5fac4dadded8a9f634166b9ed..a0b2c901c916b80728c4ef575f0d3f8fbfe96438 100644 --- a/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java +++ b/llap-server/src/java/org/apache/hadoop/hive/llap/cli/service/LlapServiceCommandLine.java @@ -174,6 +174,7 @@ private static final String OPTION_LOGLEVEL = "loglevel"; private static final String OPTION_SERVICE_KEYTAB_DIR = "service-keytab-dir"; private static final String OPTION_SERVICE_KEYTAB = "service-keytab"; + private static final String OPTION_SERVICE_KEYTAB_LOCAL_PATH = "service-keytab-localized-path"; private static final String OPTION_SERVICE_PRINCIPAL = "service-principal"; private static final String OPTION_SERVICE_PLACEMENT = "service-placement"; private static final String OPTION_SERVICE_DEFAULT_KEYTAB = "service-default-keytab"; @@ -239,6 +240,16 @@ .hasArg() .create()); + OPTIONS.addOption(OptionBuilder + .withLongOpt(OPTION_SERVICE_KEYTAB_LOCAL_PATH) + .withDescription("If present, Yarn will localize the keytab file provided as per " + + OPTION_SERVICE_KEYTAB_DIR + " and " + OPTION_SERVICE_KEYTAB + " to this path " + + "i.e. keytab will be reachable by LLAP daemon container on this local path. " + + "For most use cases this should be the same value as hive.llap.daemon.keytab.file.") + .withArgName(OPTION_SERVICE_KEYTAB_LOCAL_PATH) + .hasArg() + .create()); + OPTIONS.addOption(OptionBuilder .withLongOpt(OPTION_SERVICE_PRINCIPAL) .withDescription("Service AM principal; should be the user running the cluster, e.g. hive@EXAMPLE.COM") diff --git a/llap-server/src/main/resources/package.py b/llap-server/src/main/resources/package.py index c48ff79691525935ab2e3583565319c5f74b0f30..ff9a8d945dab04b83cb86c8cb4c8ce1a0cd91f31 100644 --- a/llap-server/src/main/resources/package.py +++ b/llap-server/src/main/resources/package.py @@ -10,7 +10,7 @@ import tarfile import zipfile -from templates import yarnfile, runner +from templates import yarnfile, runner, reused_keytab_localization class LlapResource(object): def __init__(self, config): @@ -88,6 +88,7 @@ def main(args): parser.add_argument("--service-appconfig-global", nargs='*', type=service_appconfig_global_property, action='append') parser.add_argument("--service-keytab-dir", default="") parser.add_argument("--service-keytab", default="") + parser.add_argument("--service-keytab-localized-path", default="") parser.add_argument("--service-principal", default="") parser.add_argument("--service-default-keytab", dest='service_default_keytab', action='store_true') parser.add_argument("--service-placement", type=int, default=4) @@ -167,7 +168,9 @@ def main(args): "placement" : args.service_placement, "health_percent": args.health_percent, "health_time_window": args.health_time_window_secs, - "health_init_delay": args.health_init_delay_secs + "health_init_delay": args.health_init_delay_secs, + "reused_keytab_src": service_keytab_path, + "reused_keytab_dst": args.service_keytab_localized_path } if not exists(output): @@ -189,6 +192,11 @@ def main(args): print "%s Packaged the files" % (strftime("%H:%M:%S", gmtime())) + if not args.service_keytab_localized_path: + vars["reused_keytab_localization"] = "" + else: + vars["reused_keytab_localization"] = reused_keytab_localization % vars + with open(join(output, "Yarnfile"), "w") as f: f.write(yarnfile % vars) diff --git a/llap-server/src/main/resources/templates.py b/llap-server/src/main/resources/templates.py index 1dc1611bf823f3223f309d0cd0177b734dc5caf3..cc36fc0d682555a74ad05b102cc50d1dbb07d66c 100644 --- a/llap-server/src/main/resources/templates.py +++ b/llap-server/src/main/resources/templates.py @@ -52,7 +52,7 @@ "APP_ROOT": "/app/install/", "APP_TMP_DIR": "/tmp/" - } + }%(reused_keytab_localization)s } } ], @@ -66,6 +66,16 @@ } """ +reused_keytab_localization = """ +,"files" : [ + { + "src_file" : "%(reused_keytab_src)s", + "dest_file" : "%(reused_keytab_dst)s", + "type" : "STATIC" + } + ] +""" + # Placement policy feature like ANTI AFFINITY is not yet merged to trunk in YARN runner = """ #!/bin/bash -e diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/tez/TezSessionState.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/tez/TezSessionState.java index 767b359219459e89991390acdc42bdac3a5f23ec..3750617f978d53a8c1d89ff3d96a01e3d56a6522 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/tez/TezSessionState.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/tez/TezSessionState.java @@ -91,6 +91,8 @@ import org.slf4j.LoggerFactory; import org.apache.hadoop.hive.ql.exec.tez.monitoring.TezJobMonitor; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; @@ -106,6 +108,7 @@ private static final String LLAP_SCHEDULER = LlapTaskSchedulerService.class.getName(); private static final String LLAP_LAUNCHER = LlapContainerLauncher.class.getName(); private static final String LLAP_TASK_COMMUNICATOR = LlapTaskCommunicator.class.getName(); + private static final String TEZ_AM_REUSED_KEYTAB_FILENAME = "hive.keytab"; private final HiveConf conf; private Path tezScratchDir; @@ -301,6 +304,7 @@ protected void openInternal(String[] additionalFilesNotFromConf, addJarLRByClass(LlapProtocolClientProxy.class, commonLocalResources); addJarLRByClass(RegistryOperations.class, commonLocalResources); } + reuseKeytabForTezAMIfRequired(llapMode, commonLocalResources); // Create environment for AM. Map amEnv = new HashMap(); @@ -392,6 +396,40 @@ public TezClient call() throws Exception { } } + /** + * Makes keytab used in HS2 propagate as localized resource to Tez AM side (to be used for ZK + * registry of LLAP) if requested by user. + * + * @param llapMode true if we're in LLAP mode, false if in container mode. + * @param commonLocalResources map of localized resources on Yarn side. + * @throws IOException + */ + private void reuseKeytabForTezAMIfRequired(boolean llapMode, + Map commonLocalResources) throws IOException { + + if (!llapMode || !UserGroupInformation.isSecurityEnabled()) { + //No-op for insecure clusters + return; + } + + if (!conf.getBoolVar(ConfVars.LLAP_USE_HS2_KEYTAB_FOR_AM_REGISTRY_KEYTAB) || + !Strings.isNullOrEmpty(conf.getVar(ConfVars.LLAP_TASK_SCHEDULER_AM_REGISTRY_KEYTAB_FILE))) { + //No-op if reuse of keytab is not allowed, or if Tez AM keytab location is already set + return; + } + + String hs2Keytab = conf.getVar(ConfVars.HIVE_SERVER2_KERBEROS_KEYTAB); + Preconditions.checkNotNull(hs2Keytab); + Path srcPath = new Path(hs2Keytab); + + Path destPath = new Path(TEZ_AM_REUSED_KEYTAB_FILENAME); + conf.setVar(ConfVars.LLAP_TASK_SCHEDULER_AM_REGISTRY_KEYTAB_FILE, + TEZ_AM_REUSED_KEYTAB_FILENAME); + + commonLocalResources.put(TEZ_AM_REUSED_KEYTAB_FILENAME, + utils.localizeResource(srcPath, destPath, LocalResourceType.FILE, conf)); + } + private static Token getLlapToken( String user, final Configuration conf) throws IOException { // TODO: parts of this should be moved out of TezSession to reuse the clients, but there's