AMBARI-21613. Dynamically determine what keytab files have been distributed (amagyar)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/a45e8f4f Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/a45e8f4f Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/a45e8f4f Branch: refs/heads/branch-feature-logsearch-ui Commit: a45e8f4f5e6a214cab98896092bc7d7d588a518b Parents: b17225d Author: Attila Magyar <amag...@hortonworks.com> Authored: Thu Aug 3 12:01:04 2017 +0200 Committer: Attila Magyar <amag...@hortonworks.com> Committed: Thu Aug 3 12:01:04 2017 +0200 ---------------------------------------------------------------------- .../resource_management/core/resources/klist.py | 45 ++++++++++++++++++ .../ambari/server/agent/HeartBeatHandler.java | 10 ++-- .../ambari/server/agent/HeartbeatProcessor.java | 34 ++++++++++++- .../server/controller/KerberosHelperImpl.java | 45 +++++++++++++++++- .../KERBEROS/1.10.3-10/metainfo.xml | 8 ++++ .../package/scripts/kerberos_client.py | 3 ++ .../package/scripts/kerberos_common.py | 50 +++++++++++++++++++- .../PERF/1.0/services/KERBEROS/metainfo.xml | 8 ++++ .../KERBEROS/package/scripts/kerberos_client.py | 2 + .../KERBEROS/package/scripts/kerberos_common.py | 48 +++++++++++++++++++ .../server/agent/TestHeartbeatHandler.java | 5 +- .../server/controller/KerberosHelperTest.java | 24 ++++++++-- .../stacks/2.2/KERBEROS/test_kerberos_client.py | 23 +++++++++ 13 files changed, 290 insertions(+), 15 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-common/src/main/python/resource_management/core/resources/klist.py ---------------------------------------------------------------------- diff --git a/ambari-common/src/main/python/resource_management/core/resources/klist.py b/ambari-common/src/main/python/resource_management/core/resources/klist.py new file mode 100644 index 0000000..ec6fca8 --- /dev/null +++ b/ambari-common/src/main/python/resource_management/core/resources/klist.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +""" +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. + +Ambari Agent + +""" + +from resource_management.core import shell +from resource_management import functions +from resource_management.libraries.functions.default import default +from subprocess import PIPE + +class Klist: + @staticmethod + def find_in_search_path(): + return Klist(functions.get_klist_path(default('/configurations/kerberos-env/executable_search_paths', None))) + + def __init__(self, klist_cmd="klist"): + self.klist_cmd = klist_cmd + + def list_principals(self, keytab_path): + code, out, err = shell.call(self._command('-k', keytab_path), stdout = PIPE, stderr = PIPE, timeout = 5, sudo=True) + if code != 0 or (not out.startswith("Keytab name")): + raise Exception('Cannot run klist: %s. Exit code: %d. Error: %s' % (self.klist_cmd, code, err)) + return set(line.split()[1] for line in out.split("\n")[3:]) + + def _command(self, *args): + cmd = [self.klist_cmd] + cmd.extend(args) + return cmd \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java index 1bc4c36..92ab3de 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartBeatHandler.java @@ -17,6 +17,10 @@ */ package org.apache.ambari.server.agent; +import static org.apache.ambari.server.controller.KerberosHelperImpl.CHECK_KEYTABS; +import static org.apache.ambari.server.controller.KerberosHelperImpl.REMOVE_KEYTAB; +import static org.apache.ambari.server.controller.KerberosHelperImpl.SET_KEYTAB; + import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -294,7 +298,7 @@ public class HeartBeatHandler { Map<String, String> hlp = ec.getHostLevelParams(); if (hlp != null) { String customCommand = hlp.get("custom_command"); - if ("SET_KEYTAB".equalsIgnoreCase(customCommand) || "REMOVE_KEYTAB".equalsIgnoreCase(customCommand)) { + if (SET_KEYTAB.equalsIgnoreCase(customCommand) || REMOVE_KEYTAB.equalsIgnoreCase(customCommand) || CHECK_KEYTABS.equalsIgnoreCase(customCommand)) { LOG.info(String.format("%s called", customCommand)); try { injectKeytab(ec, customCommand, hostname); @@ -593,7 +597,7 @@ public class HeartBeatHandler { if (targetHost.equalsIgnoreCase(hostName)) { - if ("SET_KEYTAB".equalsIgnoreCase(command)) { + if (SET_KEYTAB.equalsIgnoreCase(command)) { String keytabFilePath = record.get(KerberosIdentityDataFileReader.KEYTAB_FILE_PATH); if (keytabFilePath != null) { @@ -629,7 +633,7 @@ public class HeartBeatHandler { kcp.add(keytabMap); } } - } else if ("REMOVE_KEYTAB".equalsIgnoreCase(command)) { + } else if (REMOVE_KEYTAB.equalsIgnoreCase(command) || CHECK_KEYTABS.equalsIgnoreCase(command)) { Map<String, String> keytabMap = new HashMap<>(); keytabMap.put(KerberosIdentityDataFileReader.HOSTNAME, hostName); http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java index a08abab..2690008 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/agent/HeartbeatProcessor.java @@ -18,6 +18,10 @@ package org.apache.ambari.server.agent; +import static org.apache.ambari.server.controller.KerberosHelperImpl.CHECK_KEYTABS; +import static org.apache.ambari.server.controller.KerberosHelperImpl.REMOVE_KEYTAB; +import static org.apache.ambari.server.controller.KerberosHelperImpl.SET_KEYTAB; + import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -420,8 +424,8 @@ public class HeartbeatProcessor extends AbstractService{ String customCommand = report.getCustomCommand(); - boolean adding = "SET_KEYTAB".equalsIgnoreCase(customCommand); - if (adding || "REMOVE_KEYTAB".equalsIgnoreCase(customCommand)) { + boolean adding = SET_KEYTAB.equalsIgnoreCase(customCommand); + if (adding || REMOVE_KEYTAB.equalsIgnoreCase(customCommand)) { WriteKeytabsStructuredOut writeKeytabsStructuredOut; try { writeKeytabsStructuredOut = gson.fromJson(report.getStructuredOut(), WriteKeytabsStructuredOut.class); @@ -445,6 +449,12 @@ public class HeartbeatProcessor extends AbstractService{ } } } + } else if (CHECK_KEYTABS.equalsIgnoreCase(customCommand)) { + ListKeytabsStructuredOut structuredOut = gson.fromJson(report.getStructuredOut(), ListKeytabsStructuredOut.class); + for (MissingKeytab each : structuredOut.missingKeytabs){ + LOG.info("Missing keytab: {} on host: {} principal: {}", each.keytabFilePath, hostname, each.principal); + kerberosPrincipalHostDAO.remove(each.principal, host.getHostId()); + } } } @@ -702,6 +712,26 @@ public class HeartbeatProcessor extends AbstractService{ } } + private static class ListKeytabsStructuredOut { + @SerializedName("missing_keytabs") + private final List<MissingKeytab> missingKeytabs; + + public ListKeytabsStructuredOut(List<MissingKeytab> missingKeytabs) { + this.missingKeytabs = missingKeytabs; + } + } + + private static class MissingKeytab { + @SerializedName("principal") + private final String principal; + @SerializedName("keytab_file_path") + private final String keytabFilePath; + + public MissingKeytab(String principal, String keytabFilePath) { + this.principal = principal; + this.keytabFilePath = keytabFilePath; + } + } /** * This class is used for mapping json of structured output for component START action. http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java index e5b7afd..6b50ea4 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java @@ -142,6 +142,9 @@ public class KerberosHelperImpl implements KerberosHelper { * These values are important when trying to determine the state of the cluster when adding new components */ private static final Set<State> PREVIOUSLY_INSTALLED_STATES = EnumSet.of(State.INSTALLED, State.STARTED, State.DISABLED); + public static final String CHECK_KEYTABS = "CHECK_KEYTABS"; + public static final String SET_KEYTAB = "SET_KEYTAB"; + public static final String REMOVE_KEYTAB = "REMOVE_KEYTAB"; @Inject private AmbariCustomCommandExecutionHelper customCommandExecutionHelper; @@ -3027,7 +3030,7 @@ public class KerberosHelperImpl implements KerberosHelper { ActionExecutionContext actionExecContext = new ActionExecutionContext( cluster.getClusterName(), - "SET_KEYTAB", + SET_KEYTAB, requestResourceFilters, requestParams); customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage, @@ -3042,6 +3045,39 @@ public class KerberosHelperImpl implements KerberosHelper { } /** + * Send a custom command to the KERBEROS_CLIENT to check if there are missing keytabs on each hosts. + */ + public void addCheckMissingKeytabsStage(Cluster cluster, String clusterHostInfoJson, String hostParamsJson, ServiceComponentHostServerActionEvent event, Map<String, String> commandParameters, RoleCommandOrder roleCommandOrder, RequestStageContainer requestStageContainer, List<ServiceComponentHost> serviceComponentHosts) throws AmbariException { + Stage stage = createNewStage(requestStageContainer.getLastStageId(), + cluster, + requestStageContainer.getId(), + "Checking keytabs", + StageUtils.getGson().toJson(commandParameters), + hostParamsJson); + + Collection<ServiceComponentHost> filteredComponents = filterServiceComponentHostsForHosts( + new ArrayList<>(serviceComponentHosts), getHostsWithValidKerberosClient(cluster)); + + List<String> hostsToUpdate = createUniqueHostList(filteredComponents, Collections.singleton(HostState.HEALTHY)); + Map<String, String> requestParams = new HashMap<>(); + List<RequestResourceFilter> requestResourceFilters = new ArrayList<>(); + RequestResourceFilter reqResFilter = new RequestResourceFilter(Service.Type.KERBEROS.name(), Role.KERBEROS_CLIENT.name(), hostsToUpdate); + requestResourceFilters.add(reqResFilter); + + ActionExecutionContext actionExecContext = new ActionExecutionContext( + cluster.getClusterName(), + CHECK_KEYTABS, + requestResourceFilters, + requestParams); + customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage, requestParams, null); + RoleGraph roleGraph = roleGraphFactory.createNew(roleCommandOrder); + roleGraph.build(stage); + + requestStageContainer.setClusterHostInfo(clusterHostInfoJson); + requestStageContainer.addStages(roleGraph.getStages()); + } + + /** * Filter out ServiceComponentHosts that are on on hosts in the specified set of host names. * <p/> * It is expected that the supplied collection is modifiable. It will be modified inplace. @@ -3170,7 +3206,7 @@ public class KerberosHelperImpl implements KerberosHelper { ActionExecutionContext actionExecContext = new ActionExecutionContext( cluster.getClusterName(), - "REMOVE_KEYTAB", + REMOVE_KEYTAB, requestResourceFilters, requestParams); customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage, @@ -3635,6 +3671,11 @@ public class KerberosHelperImpl implements KerberosHelper { if (kerberosDetails.manageIdentities()) { commandParameters.put(KerberosServerAction.KDC_TYPE, kerberosDetails.getKdcType().name()); + if (!regenerateAllKeytabs) { + addCheckMissingKeytabsStage(cluster, clusterHostInfoJson, hostParamsJson, event, + commandParameters, roleCommandOrder, requestStageContainer, serviceComponentHosts); + } + // ***************************************************************** // Create stage to create principals addCreatePrincipalsStage(cluster, clusterHostInfoJson, hostParamsJson, event, http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/metainfo.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/metainfo.xml b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/metainfo.xml index 6a2dd09..191028a 100644 --- a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/metainfo.xml +++ b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/metainfo.xml @@ -60,6 +60,14 @@ <timeout>1000</timeout> </commandScript> </customCommand> + <customCommand> + <name>CHECK_KEYTABS</name> + <commandScript> + <script>scripts/kerberos_client.py</script> + <scriptType>PYTHON</scriptType> + <timeout>1000</timeout> + </commandScript> + </customCommand> </customCommands> <configFiles> <configFile> http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_client.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_client.py b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_client.py index 39fdcf5..691c4b8 100644 --- a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_client.py +++ b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_client.py @@ -49,5 +49,8 @@ class KerberosClient(KerberosScript): def remove_keytab(self, env): self.delete_keytab_file() + def check_keytabs(self, env): + self.find_missing_keytabs() + if __name__ == "__main__": KerberosClient().execute() http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_common.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_common.py b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_common.py index fcd57af..21accdd 100644 --- a/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_common.py +++ b/ambari-server/src/main/resources/common-services/KERBEROS/1.10.3-10/package/scripts/kerberos_common.py @@ -36,6 +36,9 @@ from resource_management.core.source import InlineTemplate, Template, DownloadSo from utils import get_property_value from ambari_commons.os_utils import remove_file from ambari_agent import Constants +from collections import namedtuple +from resource_management.core import sudo +from resource_management.core.resources.klist import Klist class KerberosScript(Script): KRB5_REALM_PROPERTIES = [ @@ -443,4 +446,49 @@ class KerberosScript(Script): curr_content['keytabs'][principal.replace("_HOST", params.hostname)] = '_REMOVED_' - self.put_structured_out(curr_content) \ No newline at end of file + self.put_structured_out(curr_content) + + def find_missing_keytabs(self): + import params + missing_keytabs = MissingKeytabs.fromKerberosRecords(params.kerberos_command_params, params.hostname) + Logger.info(str(missing_keytabs)) + curr_content = Script.structuredOut + curr_content['missing_keytabs'] = missing_keytabs.as_dict() + self.put_structured_out(curr_content) + +class MissingKeytabs: + class Identity(namedtuple('Identity', ['principal', 'keytab_file_path'])): + @staticmethod + def fromKerberosRecord(item, hostname): + return MissingKeytabs.Identity( + get_property_value(item, 'principal').replace("_HOST", hostname), + get_property_value(item, 'keytab_file_path')) + + def __str__(self): + return "Keytab: %s Principal: %s" % (self.keytab_file_path, self.principal) + + @classmethod + def fromKerberosRecords(self, kerberos_record, hostname): + with_missing_keytab = (each for each in kerberos_record \ + if not self.keytab_exists(each) or not self.keytab_has_principal(each, hostname)) + return MissingKeytabs(set(MissingKeytabs.Identity.fromKerberosRecord(each, hostname) for each in with_missing_keytab)) + + @staticmethod + def keytab_exists(kerberos_record): + return sudo.path_exists(get_property_value(kerberos_record, 'keytab_file_path')) + + @staticmethod + def keytab_has_principal(kerberos_record, hostname): + principal = get_property_value(kerberos_record, 'principal').replace("_HOST", hostname) + keytab = get_property_value(kerberos_record, 'keytab_file_path') + klist = Klist.find_in_search_path() + return principal in klist.list_principals(keytab) + + def __init__(self, items): + self.items = items + + def as_dict(self): + return [each._asdict() for each in self.items] + + def __str__(self): + return "Missing keytabs:\n%s" % ("\n".join(map(str, self.items))) if self.items else 'No missing keytabs' http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/metainfo.xml ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/metainfo.xml b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/metainfo.xml index 0e42bda..6f833c7 100644 --- a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/metainfo.xml +++ b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/metainfo.xml @@ -60,6 +60,14 @@ <timeout>1000</timeout> </commandScript> </customCommand> + <customCommand> + <name>CHECK_KEYTABS</name> + <commandScript> + <script>scripts/kerberos_client.py</script> + <scriptType>PYTHON</scriptType> + <timeout>1000</timeout> + </commandScript> + </customCommand> </customCommands> <configFiles> <configFile> http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_client.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_client.py b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_client.py index b2cdaa6..691c4b8 100644 --- a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_client.py +++ b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_client.py @@ -49,6 +49,8 @@ class KerberosClient(KerberosScript): def remove_keytab(self, env): self.delete_keytab_file() + def check_keytabs(self, env): + self.find_missing_keytabs() if __name__ == "__main__": KerberosClient().execute() http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_common.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_common.py b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_common.py index abf58ee..d959f11 100644 --- a/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_common.py +++ b/ambari-server/src/main/resources/stacks/PERF/1.0/services/KERBEROS/package/scripts/kerberos_common.py @@ -30,6 +30,9 @@ from resource_management import * from utils import get_property_value from ambari_commons.os_utils import remove_file from ambari_agent import Constants +from collections import namedtuple +from resource_management.core import sudo +from resource_management.core.resources.klist import Klist class KerberosScript(Script): KRB5_REALM_PROPERTIES = [ @@ -430,3 +433,48 @@ class KerberosScript(Script): curr_content['keytabs'][principal.replace("_HOST", params.hostname)] = '_REMOVED_' self.put_structured_out(curr_content) + + def find_missing_keytabs(self): + import params + missing_keytabs = MissingKeytabs.fromKerberosRecords(params.kerberos_command_params, params.hostname) + Logger.info(str(missing_keytabs)) + curr_content = Script.structuredOut + curr_content['missing_keytabs'] = missing_keytabs.as_dict() + self.put_structured_out(curr_content) + +class MissingKeytabs: + class Identity(namedtuple('Identity', ['principal', 'keytab_file_path'])): + @staticmethod + def fromKerberosRecord(item, hostname): + return MissingKeytabs.Identity( + get_property_value(item, 'principal').replace("_HOST", hostname), + get_property_value(item, 'keytab_file_path')) + + def __str__(self): + return "Keytab: %s Principal: %s" % (self.keytab_file_path, self.principal) + + @classmethod + def fromKerberosRecords(self, kerberos_record, hostname): + with_missing_keytab = (each for each in kerberos_record \ + if not self.keytab_exists(each) or not self.keytab_has_principal(each, hostname)) + return MissingKeytabs(set(MissingKeytabs.Identity.fromKerberosRecord(each, hostname) for each in with_missing_keytab)) + + @staticmethod + def keytab_exists(kerberos_record): + return sudo.path_exists(get_property_value(kerberos_record, 'keytab_file_path')) + + @staticmethod + def keytab_has_principal(kerberos_record, hostname): + principal = get_property_value(kerberos_record, 'principal').replace("_HOST", hostname) + keytab = get_property_value(kerberos_record, 'keytab_file_path') + klist = Klist.find_in_search_path() + return principal in klist.list_principals(keytab) + + def __init__(self, items): + self.items = items + + def as_dict(self): + return [each._asdict() for each in self.items] + + def __str__(self): + return "Missing keytabs:\n%s" % ("\n".join(map(str, self.items))) if self.items else 'No missing keytabs' http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java index baa9bae..4235b11 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/agent/TestHeartbeatHandler.java @@ -30,6 +30,7 @@ import static org.apache.ambari.server.agent.DummyHeartbeatConstants.HDFS; import static org.apache.ambari.server.agent.DummyHeartbeatConstants.HDFS_CLIENT; import static org.apache.ambari.server.agent.DummyHeartbeatConstants.NAMENODE; import static org.apache.ambari.server.agent.DummyHeartbeatConstants.SECONDARY_NAMENODE; +import static org.apache.ambari.server.controller.KerberosHelperImpl.SET_KEYTAB; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; @@ -1476,7 +1477,7 @@ public class TestHeartbeatHandler { ExecutionCommand executionCommand = new ExecutionCommand(); Map<String, String> hlp = new HashMap<>(); - hlp.put("custom_command", "SET_KEYTAB"); + hlp.put("custom_command", SET_KEYTAB); executionCommand.setHostLevelParams(hlp); Map<String, String> commandparams = new HashMap<>(); @@ -1496,7 +1497,7 @@ public class TestHeartbeatHandler { }}); replay(am); - heartbeatTestHelper.getHeartBeatHandler(am, aq).injectKeytab(executionCommand, "SET_KEYTAB", targetHost); + heartbeatTestHelper.getHeartBeatHandler(am, aq).injectKeytab(executionCommand, SET_KEYTAB, targetHost); return executionCommand.getKerberosCommandParams(); } http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java index 4508527..0196069 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java @@ -2824,23 +2824,23 @@ public class KerberosHelperTest extends EasyMockSupport { add(schKerberosClientC); } }) - .once(); + .anyTimes(); final Clusters clusters = injector.getInstance(Clusters.class); if ((filteredHosts == null) || filteredHosts.contains("hostA")) { expect(clusters.getHost("hostA")) .andReturn(hostA) - .once(); + .anyTimes(); } if ((filteredHosts == null) || filteredHosts.contains("hostB")) { expect(clusters.getHost("hostB")) .andReturn(hostB) - .once(); + .anyTimes(); } if ((filteredHosts == null) || filteredHosts.contains("hostC")) { expect(clusters.getHost("hostC")) .andReturn(hostC) - .once(); + .anyTimes(); } final AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class); @@ -2917,6 +2917,13 @@ public class KerberosHelperTest extends EasyMockSupport { expectLastCall().once(); requestStageContainer.addStages(EasyMock.<List<Stage>>anyObject()); expectLastCall().once(); + // Getting missing keytabs + expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.setClusterHostInfo(anyString()); + expectLastCall().once(); + requestStageContainer.addStages(EasyMock.<List<Stage>>anyObject()); + expectLastCall().once(); // Create Principals Stage expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes(); expect(requestStageContainer.getId()).andReturn(1L).once(); @@ -3268,7 +3275,7 @@ public class KerberosHelperTest extends EasyMockSupport { final Clusters clusters = injector.getInstance(Clusters.class); expect(clusters.getHost("host1")) .andReturn(host) - .once(); + .anyTimes(); final AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class); expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, null)) @@ -3302,6 +3309,13 @@ public class KerberosHelperTest extends EasyMockSupport { expectLastCall().once(); requestStageContainer.addStages(EasyMock.<List<Stage>>anyObject()); expectLastCall().once(); + // Getting missing keytabs + expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.setClusterHostInfo(anyString()); + expectLastCall().once(); + requestStageContainer.addStages(EasyMock.<List<Stage>>anyObject()); + expectLastCall().once(); // Create Principals Stage expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes(); expect(requestStageContainer.getId()).andReturn(1L).once(); http://git-wip-us.apache.org/repos/asf/ambari/blob/a45e8f4f/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py b/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py index f638845..cb2db3a 100644 --- a/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py +++ b/ambari-server/src/test/python/stacks/2.2/KERBEROS/test_kerberos_client.py @@ -23,6 +23,8 @@ import os import sys import use_cases from stacks.utils.RMFTestCase import * +from resource_management import Script +from collections import OrderedDict from only_for_platform import not_for_platform, PLATFORM_WINDOWS @@ -353,3 +355,24 @@ class TestKerberosClient(RMFTestCase): # The kdc_host is expected to generated using kdc_hosts, but only the first host is used since # previous versions only knew how to handle a single KDC host self.assertEquals('c6401.ambari.apache.org', sys.modules['params'].kdc_host) + + @patch("resource_management.core.sudo.path_exists") + def test_find_missing_keytabs(self, path_exists): + path_exists.side_effect = [False] + json_data = use_cases.get_managed_kdc_use_case() + json_data['kerberosCommandParams'] = [ + { + "keytab_file_path": '/deleted_keytab', + "principal": "HTTP/_h...@example.com" + } + ] + self.executeScript(self.COMMON_SERVICES_PACKAGE_DIR + "/scripts/kerberos_client.py", + classname="KerberosClient", + command="check_keytabs", + config_dict=json_data, + stack_version=self.STACK_VERSION, + target=RMFTestCase.TARGET_COMMON_SERVICES) + self.assertEquals(Script.structuredOut['missing_keytabs'], [OrderedDict({ + 'keytab_file_path' : '/deleted_keytab', + 'principal' : 'HTTP/c6401.ambari.apache....@example.com' + })]) \ No newline at end of file