You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by rl...@apache.org on 2017/06/30 09:46:42 UTC
[26/33] ambari git commit: AMBARI-21343. Cleanup relevant Kerberos
identities when a component is removed (amagyar)
AMBARI-21343. Cleanup relevant Kerberos identities when a component is removed (amagyar)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/8b5c7db6
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/8b5c7db6
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/8b5c7db6
Branch: refs/heads/branch-feature-AMBARI-20859
Commit: 8b5c7db602a0e1e2dfb214ec1d51884c16219467
Parents: 9d224f7
Author: Attila Magyar <am...@hortonworks.com>
Authored: Thu Jun 29 11:05:25 2017 +0200
Committer: Attila Magyar <am...@hortonworks.com>
Committed: Thu Jun 29 11:05:25 2017 +0200
----------------------------------------------------------------------
.../ambari/server/controller/AmbariServer.java | 4 +
.../controller/DeleteIdentityHandler.java | 283 +++++++++++++++++++
.../server/controller/KerberosHelper.java | 3 +
.../server/controller/KerberosHelperImpl.java | 31 +-
.../OrderedRequestStageContainer.java | 45 +++
.../utilities/KerberosIdentityCleaner.java | 135 +++++++++
.../AbstractPrepareKerberosServerAction.java | 19 +-
.../server/serveraction/kerberos/Component.java | 74 +++++
.../kerberos/FinalizeKerberosServerAction.java | 27 +-
.../kerberos/KerberosServerAction.java | 27 ++
.../kerberos/AbstractKerberosDescriptor.java | 15 +
.../kerberos/KerberosComponentDescriptor.java | 15 +
.../state/kerberos/KerberosDescriptor.java | 8 -
.../kerberos/KerberosIdentityDescriptor.java | 30 ++
.../kerberos/KerberosServiceDescriptor.java | 6 +
.../utilities/KerberosIdentityCleanerTest.java | 204 +++++++++++++
ambari-web/app/controllers/main/service/item.js | 6 +-
17 files changed, 894 insertions(+), 38 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
index aeba739..8988be0 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariServer.java
@@ -76,6 +76,7 @@ import org.apache.ambari.server.controller.internal.UserPrivilegeResourceProvide
import org.apache.ambari.server.controller.internal.ViewPermissionResourceProvider;
import org.apache.ambari.server.controller.metrics.ThreadPoolEnabledPropertyProvider;
import org.apache.ambari.server.controller.utilities.KerberosChecker;
+import org.apache.ambari.server.controller.utilities.KerberosIdentityCleaner;
import org.apache.ambari.server.metrics.system.MetricsService;
import org.apache.ambari.server.orm.GuiceJpaInitializer;
import org.apache.ambari.server.orm.PersistenceType;
@@ -941,6 +942,9 @@ public class AmbariServer {
BaseService.init(injector.getInstance(RequestAuditLogger.class));
RetryHelper.init(injector.getInstance(Clusters.class), configs.getOperationsRetryAttempts());
+
+ KerberosIdentityCleaner identityCleaner = injector.getInstance(KerberosIdentityCleaner.class);
+ identityCleaner.register();
}
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/controller/DeleteIdentityHandler.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/DeleteIdentityHandler.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/DeleteIdentityHandler.java
new file mode 100644
index 0000000..aa098b6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/DeleteIdentityHandler.java
@@ -0,0 +1,283 @@
+/*
+ * 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.ambari.server.controller;
+
+import static com.google.common.collect.Sets.newHashSet;
+import static org.apache.ambari.server.controller.KerberosHelperImpl.BASE_LOG_DIR;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.Role;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.actionmanager.StageFactory;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.ambari.server.controller.internal.RequestResourceFilter;
+import org.apache.ambari.server.serveraction.ServerAction;
+import org.apache.ambari.server.serveraction.kerberos.AbstractPrepareKerberosServerAction;
+import org.apache.ambari.server.serveraction.kerberos.Component;
+import org.apache.ambari.server.serveraction.kerberos.DestroyPrincipalsServerAction;
+import org.apache.ambari.server.serveraction.kerberos.KDCType;
+import org.apache.ambari.server.serveraction.kerberos.KerberosOperationHandler;
+import org.apache.ambari.server.serveraction.kerberos.KerberosServerAction;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent;
+import org.apache.ambari.server.utils.StageUtils;
+
+/**
+ * I delete kerberos identities (principals and keytabs) of a given component.
+ */
+class DeleteIdentityHandler {
+ private final AmbariCustomCommandExecutionHelper customCommandExecutionHelper;
+ private final Integer taskTimeout;
+ private final StageFactory stageFactory;
+ private final AmbariManagementController ambariManagementController;
+
+ public DeleteIdentityHandler(AmbariCustomCommandExecutionHelper customCommandExecutionHelper, Integer taskTimeout, StageFactory stageFactory, AmbariManagementController ambariManagementController) {
+ this.customCommandExecutionHelper = customCommandExecutionHelper;
+ this.taskTimeout = taskTimeout;
+ this.stageFactory = stageFactory;
+ this.ambariManagementController = ambariManagementController;
+ }
+
+ /**
+ * Creates and adds stages to the given stage container for deleting kerberos identities.
+ * The service component that belongs to the identity doesn't need to be installed.
+ */
+ public void addDeleteIdentityStages(Cluster cluster, OrderedRequestStageContainer stageContainer, CommandParams commandParameters, boolean manageIdentities)
+ throws AmbariException
+ {
+ ServiceComponentHostServerActionEvent event = new ServiceComponentHostServerActionEvent("AMBARI_SERVER", StageUtils.getHostName(), System.currentTimeMillis());
+ String hostParamsJson = StageUtils.getGson().toJson(customCommandExecutionHelper.createDefaultHostParams(cluster, cluster.getDesiredStackVersion()));
+ stageContainer.setClusterHostInfo(StageUtils.getGson().toJson(StageUtils.getClusterHostInfo(cluster)));
+ if (manageIdentities) {
+ addPrepareDeleteIdentity(cluster, hostParamsJson, event, commandParameters, stageContainer);
+ addDestroyPrincipals(cluster, hostParamsJson, event, commandParameters, stageContainer);
+ addDeleteKeytab(cluster, newHashSet(commandParameters.component.getHostName()), hostParamsJson, commandParameters, stageContainer);
+ }
+ addFinalize(cluster, hostParamsJson, event, stageContainer, commandParameters);
+ }
+
+ private void addPrepareDeleteIdentity(Cluster cluster,
+ String hostParamsJson, ServiceComponentHostServerActionEvent event,
+ CommandParams commandParameters,
+ OrderedRequestStageContainer stageContainer)
+ throws AmbariException
+ {
+ Stage stage = createServerActionStage(stageContainer.getLastStageId(),
+ cluster,
+ stageContainer.getId(),
+ "Prepare delete identities",
+ "{}",
+ hostParamsJson,
+ PrepareDeleteIdentityServerAction.class,
+ event,
+ commandParameters.asMap(),
+ "Prepare delete identities",
+ taskTimeout);
+ stageContainer.addStage(stage);
+ }
+
+ private void addDestroyPrincipals(Cluster cluster,
+ String hostParamsJson, ServiceComponentHostServerActionEvent event,
+ CommandParams commandParameters,
+ OrderedRequestStageContainer stageContainer)
+ throws AmbariException
+ {
+ Stage stage = createServerActionStage(stageContainer.getLastStageId(),
+ cluster,
+ stageContainer.getId(),
+ "Destroy Principals",
+ "{}",
+ hostParamsJson,
+ DestroyPrincipalsServerAction.class,
+ event,
+ commandParameters.asMap(),
+ "Destroy Principals",
+ Math.max(ServerAction.DEFAULT_LONG_RUNNING_TASK_TIMEOUT_SECONDS, taskTimeout));
+ stageContainer.addStage(stage);
+ }
+
+ private void addDeleteKeytab(Cluster cluster,
+ Set<String> hostFilter,
+ String hostParamsJson,
+ CommandParams commandParameters,
+ OrderedRequestStageContainer stageContainer)
+ throws AmbariException
+ {
+ Stage stage = createNewStage(stageContainer.getLastStageId(),
+ cluster,
+ stageContainer.getId(),
+ "Delete Keytabs",
+ commandParameters.asJson(),
+ hostParamsJson);
+
+ Map<String, String> requestParams = new HashMap<>();
+ List<RequestResourceFilter> requestResourceFilters = new ArrayList<>();
+ RequestResourceFilter reqResFilter = new RequestResourceFilter("KERBEROS", "KERBEROS_CLIENT", new ArrayList<>(hostFilter));
+ requestResourceFilters.add(reqResFilter);
+
+ ActionExecutionContext actionExecContext = new ActionExecutionContext(
+ cluster.getClusterName(),
+ "REMOVE_KEYTAB",
+ requestResourceFilters,
+ requestParams);
+ customCommandExecutionHelper.addExecutionCommandsToStage(actionExecContext, stage, requestParams, null);
+ stageContainer.addStage(stage);
+ }
+
+ private void addFinalize(Cluster cluster,
+ String hostParamsJson, ServiceComponentHostServerActionEvent event,
+ OrderedRequestStageContainer requestStageContainer,
+ CommandParams commandParameters)
+ throws AmbariException
+ {
+ Stage stage = createServerActionStage(requestStageContainer.getLastStageId(),
+ cluster,
+ requestStageContainer.getId(),
+ "Finalize Operations",
+ "{}",
+ hostParamsJson,
+ DeleteDataDirAction.class,
+ event,
+ commandParameters.asMap(),
+ "Finalize Operations", 300);
+ requestStageContainer.addStage(stage);
+ }
+
+
+ public static class CommandParams {
+ private final Component component;
+ private final List<String> identities;
+ private final String authName;
+ private final File dataDirectory;
+ private final String defaultRealm;
+ private final KDCType kdcType;
+
+ public CommandParams(Component component, List<String> identities, String authName, File dataDirectory, String defaultRealm, KDCType kdcType) {
+ this.component = component;
+ this.identities = identities;
+ this.authName = authName;
+ this.dataDirectory = dataDirectory;
+ this.defaultRealm = defaultRealm;
+ this.kdcType = kdcType;
+ }
+
+ public Map<String, String> asMap() {
+ Map<String, String> commandParameters = new HashMap<>();
+ commandParameters.put(KerberosServerAction.AUTHENTICATED_USER_NAME, authName);
+ commandParameters.put(KerberosServerAction.DEFAULT_REALM, defaultRealm);
+ commandParameters.put(KerberosServerAction.KDC_TYPE, kdcType.name());
+ commandParameters.put(KerberosServerAction.IDENTITY_FILTER, StageUtils.getGson().toJson(identities));
+ commandParameters.put(KerberosServerAction.COMPONENT_FILTER, StageUtils.getGson().toJson(component));
+ commandParameters.put(KerberosServerAction.DATA_DIRECTORY, dataDirectory.getAbsolutePath());
+ return commandParameters;
+ }
+
+ public String asJson() {
+ return StageUtils.getGson().toJson(asMap());
+ }
+ }
+
+ private static class PrepareDeleteIdentityServerAction extends AbstractPrepareKerberosServerAction {
+ @Override
+ public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException {
+ KerberosDescriptor kerberosDescriptor = getKerberosDescriptor();
+ processServiceComponents(
+ getCluster(),
+ kerberosDescriptor,
+ Collections.singletonList(getComponentFilter()),
+ getIdentityFilter(),
+ dataDirectory(),
+ calculateConfig(kerberosDescriptor),
+ new HashMap<String, Map<String, String>>(),
+ false,
+ new HashMap<String, Set<String>>());
+ return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ }
+
+ protected Component getComponentFilter() {
+ return StageUtils.getGson().fromJson(getCommandParameterValue(KerberosServerAction.COMPONENT_FILTER), Component.class);
+ }
+
+ private Map<String, Map<String, String>> calculateConfig(KerberosDescriptor kerberosDescriptor) throws AmbariException {
+ return getKerberosHelper().calculateConfigurations(getCluster(), null, kerberosDescriptor.getProperties());
+ }
+
+ private String dataDirectory() {
+ return getCommandParameterValue(getCommandParameters(), DATA_DIRECTORY);
+ }
+
+ private KerberosDescriptor getKerberosDescriptor() throws AmbariException {
+ return getKerberosHelper().getKerberosDescriptor(getCluster());
+ }
+ }
+
+ private Stage createNewStage(long id, Cluster cluster, long requestId, String requestContext, String commandParams, String hostParams) {
+ Stage stage = stageFactory.createNew(requestId,
+ BASE_LOG_DIR + File.pathSeparator + requestId,
+ cluster.getClusterName(),
+ cluster.getClusterId(),
+ requestContext,
+ commandParams,
+ hostParams);
+ stage.setStageId(id);
+ return stage;
+ }
+
+ private Stage createServerActionStage(long id, Cluster cluster, long requestId,
+ String requestContext,
+ String commandParams, String hostParams,
+ Class<? extends ServerAction> actionClass,
+ ServiceComponentHostServerActionEvent event,
+ Map<String, String> commandParameters, String commandDetail,
+ Integer timeout) throws AmbariException {
+
+ Stage stage = createNewStage(id, cluster, requestId, requestContext, commandParams, hostParams);
+ stage.addServerActionCommand(actionClass.getName(), null, Role.AMBARI_SERVER_ACTION,
+ RoleCommand.EXECUTE, cluster.getClusterName(), event, commandParameters, commandDetail,
+ ambariManagementController.findConfigurationTagsWithOverrides(cluster, null), timeout,
+ false, false);
+
+ return stage;
+ }
+
+ private static class DeleteDataDirAction extends KerberosServerAction {
+
+ @Override
+ public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException {
+ deleteDataDirectory(getCommandParameterValue(DATA_DIRECTORY));
+ return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
+ }
+
+ @Override
+ protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal, KerberosOperationHandler operationHandler, Map<String, String> kerberosConfiguration, Map<String, Object> requestSharedDataContext) throws AmbariException {
+ return null;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
index ca2dda5..cc0c048 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
@@ -27,6 +27,7 @@ import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.controller.internal.RequestStageContainer;
import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
+import org.apache.ambari.server.serveraction.kerberos.Component;
import org.apache.ambari.server.serveraction.kerberos.KerberosAdminAuthenticationException;
import org.apache.ambari.server.serveraction.kerberos.KerberosIdentityDataFileWriter;
import org.apache.ambari.server.serveraction.kerberos.KerberosInvalidConfigurationException;
@@ -232,6 +233,8 @@ public interface KerberosHelper {
RequestStageContainer requestStageContainer, Boolean manageIdentities)
throws AmbariException, KerberosOperationException;
+ void deleteIdentity(Cluster cluster, Component component, List<String> identities) throws AmbariException, KerberosOperationException;
+
/**
* Updates the relevant configurations for the components specified in the service filter.
* <p/>
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/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 d57fcd2..b30f8f6 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
@@ -64,6 +64,7 @@ import org.apache.ambari.server.security.credential.PrincipalKeyCredential;
import org.apache.ambari.server.security.encryption.CredentialStoreService;
import org.apache.ambari.server.serveraction.ServerAction;
import org.apache.ambari.server.serveraction.kerberos.CleanupServerAction;
+import org.apache.ambari.server.serveraction.kerberos.Component;
import org.apache.ambari.server.serveraction.kerberos.ConfigureAmbariIdentitiesServerAction;
import org.apache.ambari.server.serveraction.kerberos.CreateKeytabFilesServerAction;
import org.apache.ambari.server.serveraction.kerberos.CreatePrincipalsServerAction;
@@ -130,7 +131,7 @@ import com.google.inject.persist.Transactional;
@Singleton
public class KerberosHelperImpl implements KerberosHelper {
- private static final String BASE_LOG_DIR = "/tmp/ambari";
+ public static final String BASE_LOG_DIR = "/tmp/ambari";
private static final Logger LOG = LoggerFactory.getLogger(KerberosHelperImpl.class);
@@ -296,6 +297,34 @@ public class KerberosHelperImpl implements KerberosHelper {
requestStageContainer, new DeletePrincipalsAndKeytabsHandler());
}
+ /**
+ * Deletes the kerberos identities of the given component, even if the component is already deleted.
+ */
+ @Override
+ public void deleteIdentity(Cluster cluster, Component component, List<String> identities) throws AmbariException, KerberosOperationException {
+ if (identities.isEmpty()) {
+ return;
+ }
+ KerberosDetails kerberosDetails = getKerberosDetails(cluster, null);
+ validateKDCCredentials(kerberosDetails, cluster);
+ File dataDirectory = createTemporaryDirectory();
+ RoleCommandOrder roleCommandOrder = ambariManagementController.getRoleCommandOrder(cluster);
+ DeleteIdentityHandler handler = new DeleteIdentityHandler(customCommandExecutionHelper, configuration.getDefaultServerTaskTimeout(), stageFactory, ambariManagementController);
+ DeleteIdentityHandler.CommandParams commandParameters = new DeleteIdentityHandler.CommandParams(
+ component,
+ identities,
+ ambariManagementController.getAuthName(),
+ dataDirectory,
+ kerberosDetails.getDefaultRealm(),
+ kerberosDetails.getKdcType());
+ OrderedRequestStageContainer stageContainer = new OrderedRequestStageContainer(
+ roleGraphFactory,
+ roleCommandOrder,
+ new RequestStageContainer(actionManager.getNextRequestId(), null, requestFactory, actionManager));
+ handler.addDeleteIdentityStages(cluster, stageContainer, commandParameters, kerberosDetails.manageIdentities());
+ stageContainer.getRequestStageContainer().persist();
+ }
+
@Override
public void configureServices(Cluster cluster, Map<String, Collection<String>> serviceFilter)
throws AmbariException, KerberosInvalidConfigurationException {
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/controller/OrderedRequestStageContainer.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/OrderedRequestStageContainer.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/OrderedRequestStageContainer.java
new file mode 100644
index 0000000..6d8b5a3
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/OrderedRequestStageContainer.java
@@ -0,0 +1,45 @@
+package org.apache.ambari.server.controller;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.controller.internal.RequestStageContainer;
+import org.apache.ambari.server.metadata.RoleCommandOrder;
+import org.apache.ambari.server.stageplanner.RoleGraph;
+import org.apache.ambari.server.stageplanner.RoleGraphFactory;
+
+/**
+ * An extension of RequestStageContainer that takes the role command order into consideration when adding stages
+ */
+public class OrderedRequestStageContainer {
+ private final RoleGraphFactory roleGraphFactory;
+ private final RoleCommandOrder roleCommandOrder;
+ private final RequestStageContainer requestStageContainer;
+
+ public OrderedRequestStageContainer(RoleGraphFactory roleGraphFactory, RoleCommandOrder roleCommandOrder, RequestStageContainer requestStageContainer) {
+ this.roleGraphFactory = roleGraphFactory;
+ this.roleCommandOrder = roleCommandOrder;
+ this.requestStageContainer = requestStageContainer;
+ }
+
+ public void addStage(Stage stage) throws AmbariException {
+ RoleGraph roleGraph = roleGraphFactory.createNew(roleCommandOrder);
+ roleGraph.build(stage);
+ requestStageContainer.addStages(roleGraph.getStages());
+ }
+
+ public long getLastStageId() {
+ return requestStageContainer.getLastStageId();
+ }
+
+ public long getId() {
+ return requestStageContainer.getId();
+ }
+
+ public RequestStageContainer getRequestStageContainer() {
+ return requestStageContainer;
+ }
+
+ public void setClusterHostInfo(String clusterHostInfo) {
+ this.requestStageContainer.setClusterHostInfo(clusterHostInfo);
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleaner.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleaner.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleaner.java
new file mode 100644
index 0000000..0a8462f
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleaner.java
@@ -0,0 +1,135 @@
+/*
+ * 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.ambari.server.controller.utilities;
+
+import static org.apache.ambari.server.state.kerberos.AbstractKerberosDescriptor.nullToEmpty;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.events.ServiceComponentUninstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.serveraction.kerberos.Component;
+import org.apache.ambari.server.serveraction.kerberos.KerberosMissingAdminCredentialsException;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.SecurityType;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.eventbus.Subscribe;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+@Singleton
+public class KerberosIdentityCleaner {
+ private final static Logger LOG = LoggerFactory.getLogger(KerberosIdentityCleaner.class);
+ private final AmbariEventPublisher eventPublisher;
+ private final KerberosHelper kerberosHelper;
+ private final Clusters clusters;
+
+ @Inject
+ public KerberosIdentityCleaner(AmbariEventPublisher eventPublisher, KerberosHelper kerberosHelper, Clusters clusters) {
+ this.eventPublisher = eventPublisher;
+ this.kerberosHelper = kerberosHelper;
+ this.clusters = clusters;
+ }
+
+ public void register() {
+ this.eventPublisher.register(this);
+ }
+
+ /**
+ * Removes kerberos identities (principals and keytabs) after a component was uninstalled.
+ * Keeps the identity if either the principal or the keytab is used by an other service
+ */
+ @Subscribe
+ public void componentRemoved(ServiceComponentUninstalledEvent event) throws KerberosMissingAdminCredentialsException {
+ try {
+ Cluster cluster = clusters.getCluster(event.getClusterId());
+ if (cluster.getSecurityType() != SecurityType.KERBEROS) {
+ return;
+ }
+ KerberosComponentDescriptor descriptor = componentDescriptor(cluster, event.getServiceName(), event.getComponentName());
+ if (descriptor == null) {
+ LOG.info("No kerberos descriptor for {}", event);
+ return;
+ }
+ List<String> identitiesToRemove = identityNames(skipSharedIdentities(descriptor.getIdentitiesSkipReferences(), cluster, event));
+ LOG.info("Deleting identities {} after an event {}", identitiesToRemove, event);
+ kerberosHelper.deleteIdentity(cluster, new Component(event.getHostName(), event.getServiceName(), event.getComponentName()), identitiesToRemove);
+ } catch (Exception e) {
+ LOG.error("Error while deleting kerberos identity after an event: " + event, e);
+ }
+ }
+
+ private KerberosComponentDescriptor componentDescriptor(Cluster cluster, String serviceName, String componentName) throws AmbariException {
+ KerberosServiceDescriptor serviceDescriptor = kerberosHelper.getKerberosDescriptor(cluster).getService(serviceName);
+ return serviceDescriptor == null ? null : serviceDescriptor.getComponent(componentName);
+ }
+
+ private List<String> identityNames(List<KerberosIdentityDescriptor> identities) {
+ List<String> result = new ArrayList<>();
+ for (KerberosIdentityDescriptor each : identities) { result.add(each.getName()); }
+ return result;
+ }
+
+ private List<KerberosIdentityDescriptor> skipSharedIdentities(List<KerberosIdentityDescriptor> candidates, Cluster cluster, ServiceComponentUninstalledEvent event) throws AmbariException {
+ List<KerberosIdentityDescriptor> activeIdentities = activeIdentities(cluster, kerberosHelper.getKerberosDescriptor(cluster), event);
+ List<KerberosIdentityDescriptor> result = new ArrayList<>();
+ for (KerberosIdentityDescriptor candidate : candidates) {
+ if (!candidate.isShared(activeIdentities)) {
+ result.add(candidate);
+ } else {
+ LOG.debug("Skip removing shared identity: {}", candidate.getName());
+ }
+ }
+ return result;
+ }
+
+ private List<KerberosIdentityDescriptor> activeIdentities(Cluster cluster, KerberosDescriptor root, ServiceComponentUninstalledEvent event) {
+ List<KerberosIdentityDescriptor> result = new ArrayList<>();
+ result.addAll(nullToEmpty(root.getIdentities()));
+ for (Map.Entry<String, Service> serviceEntry : cluster.getServices().entrySet()) {
+ KerberosServiceDescriptor serviceDescriptor = root.getService(serviceEntry.getKey());
+ if (serviceDescriptor == null) {
+ continue;
+ }
+ result.addAll(nullToEmpty(serviceDescriptor.getIdentities()));
+ for (String componentName : serviceEntry.getValue().getServiceComponents().keySet()) {
+ if (!sameComponent(event, componentName, serviceEntry.getKey())) {
+ result.addAll(serviceDescriptor.getComponentIdentities(componentName));
+ }
+ }
+ }
+ return result;
+ }
+
+ private boolean sameComponent(ServiceComponentUninstalledEvent event, String componentName, String serviceName) {
+ return event.getServiceName().equals(serviceName) && event.getComponentName().equals(componentName);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
index 7aac346..dd2b223 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/AbstractPrepareKerberosServerAction.java
@@ -21,6 +21,7 @@ package org.apache.ambari.server.serveraction.kerberos;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -65,7 +66,7 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
throw new UnsupportedOperationException();
}
- KerberosHelper getKerberosHelper() {
+ protected KerberosHelper getKerberosHelper() {
return kerberosHelper;
}
@@ -76,6 +77,20 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
Map<String, Map<String, String>> kerberosConfigurations,
boolean includeAmbariIdentity,
Map<String, Set<String>> propertiesToBeIgnored) throws AmbariException {
+ List<Component> components = new ArrayList<>();
+ for (ServiceComponentHost each : schToProcess) {
+ components.add(Component.fromServiceComponentHost(each));
+ }
+ processServiceComponents(cluster, kerberosDescriptor, components, identityFilter, dataDirectory, currentConfigurations, kerberosConfigurations, includeAmbariIdentity, propertiesToBeIgnored);
+ }
+
+ protected void processServiceComponents(Cluster cluster, KerberosDescriptor kerberosDescriptor,
+ List<Component> schToProcess,
+ Collection<String> identityFilter, String dataDirectory,
+ Map<String, Map<String, String>> currentConfigurations,
+ Map<String, Map<String, String>> kerberosConfigurations,
+ boolean includeAmbariIdentity,
+ Map<String, Set<String>> propertiesToBeIgnored) throws AmbariException {
actionLog.writeStdOut("Processing Kerberos identities and configurations");
@@ -113,7 +128,7 @@ public abstract class AbstractPrepareKerberosServerAction extends KerberosServer
// Iterate over the components installed on the current host to get the service and
// component-level Kerberos descriptors in order to determine which principals,
// keytab files, and configurations need to be created or updated.
- for (ServiceComponentHost sch : schToProcess) {
+ for (Component sch : schToProcess) {
String hostName = sch.getHostName();
String serviceName = sch.getServiceName();
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/Component.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/Component.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/Component.java
new file mode 100644
index 0000000..4f1ee52
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/Component.java
@@ -0,0 +1,74 @@
+/*
+ * 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.ambari.server.serveraction.kerberos;
+
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+
+public class Component {
+ private final String hostName;
+ private final String serviceName;
+ private final String serviceComponentName;
+
+ public static Component fromServiceComponentHost(ServiceComponentHost serviceComponentHost) {
+ return new Component(
+ serviceComponentHost.getHostName(),
+ serviceComponentHost.getServiceName(),
+ serviceComponentHost.getServiceComponentName());
+ }
+
+ public Component(String hostName, String serviceName, String serviceComponentName) {
+ this.hostName = hostName;
+ this.serviceName = serviceName;
+ this.serviceComponentName = serviceComponentName;
+ }
+
+ public String getHostName() {
+ return hostName;
+ }
+
+ public String getServiceName() {
+ return serviceName;
+ }
+
+ public String getServiceComponentName() {
+ return serviceComponentName;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Component component = (Component) o;
+ return new EqualsBuilder()
+ .append(hostName, component.hostName)
+ .append(serviceName, component.serviceName)
+ .append(serviceComponentName, component.serviceComponentName)
+ .isEquals();
+ }
+
+ @Override
+ public int hashCode() {
+ return new HashCodeBuilder(17, 37)
+ .append(hostName)
+ .append(serviceName)
+ .append(serviceComponentName)
+ .toHashCode();
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
index 2742390..10ad48b 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
@@ -18,8 +18,6 @@
package org.apache.ambari.server.serveraction.kerberos;
-import java.io.File;
-import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -36,7 +34,6 @@ import org.apache.ambari.server.state.SecurityState;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.utils.ShellCommandUtil;
import org.apache.ambari.server.utils.StageUtils;
-import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -208,29 +205,9 @@ public class FinalizeKerberosServerAction extends KerberosServerAction {
processIdentities(requestSharedDataContext);
requestSharedDataContext.remove(this.getClass().getName() + "_visited");
}
-
- // Make sure this is a relevant directory. We don't want to accidentally allow _ANY_ directory
- // to be deleted.
- if ((dataDirectoryPath != null) && dataDirectoryPath.contains("/" + DATA_DIRECTORY_PREFIX)) {
- File dataDirectory = new File(dataDirectoryPath);
- File dataDirectoryParent = dataDirectory.getParentFile();
-
- // Make sure this directory has a parent and it is writeable, else we wont be able to
- // delete the directory
- if ((dataDirectoryParent != null) && dataDirectory.isDirectory() &&
- dataDirectoryParent.isDirectory() && dataDirectoryParent.canWrite()) {
- try {
- FileUtils.deleteDirectory(dataDirectory);
- } catch (IOException e) {
- // We should log this exception, but don't let it fail the process since if we got to this
- // KerberosServerAction it is expected that the the overall process was a success.
- String message = String.format("The data directory (%s) was not deleted due to an error condition - {%s}",
- dataDirectory.getAbsolutePath(), e.getMessage());
- LOG.warn(message, e);
- }
- }
- }
+ deleteDataDirectory(dataDirectoryPath);
return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", actionLog.getStdOut(), actionLog.getStdErr());
}
+
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
index d404133..2e331bb 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerAction.java
@@ -35,6 +35,7 @@ import org.apache.ambari.server.serveraction.AbstractServerAction;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -82,6 +83,8 @@ public abstract class KerberosServerAction extends AbstractServerAction {
*/
public static final String IDENTITY_FILTER = "identity_filter";
+ public static final String COMPONENT_FILTER = "component_filter";
+
/**
* A (command parameter) property name used to hold the relevant KDC type value. See
* {@link org.apache.ambari.server.serveraction.kerberos.KDCType} for valid values
@@ -536,4 +539,28 @@ public abstract class KerberosServerAction extends AbstractServerAction {
return commandReport;
}
+
+ protected void deleteDataDirectory(String dataDirectoryPath) {
+ // Make sure this is a relevant directory. We don't want to accidentally allow _ANY_ directory
+ // to be deleted.
+ if ((dataDirectoryPath != null) && dataDirectoryPath.contains("/" + DATA_DIRECTORY_PREFIX)) {
+ File dataDirectory = new File(dataDirectoryPath);
+ File dataDirectoryParent = dataDirectory.getParentFile();
+
+ // Make sure this directory has a parent and it is writeable, else we wont be able to
+ // delete the directory
+ if ((dataDirectoryParent != null) && dataDirectory.isDirectory() &&
+ dataDirectoryParent.isDirectory() && dataDirectoryParent.canWrite()) {
+ try {
+ FileUtils.deleteDirectory(dataDirectory);
+ } catch (IOException e) {
+ // We should log this exception, but don't let it fail the process since if we got to this
+ // KerberosServerAction it is expected that the the overall process was a success.
+ String message = String.format("The data directory (%s) was not deleted due to an error condition - {%s}",
+ dataDirectory.getAbsolutePath(), e.getMessage());
+ LOG.warn(message, e);
+ }
+ }
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
index 397f384..38100ac 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/AbstractKerberosDescriptor.java
@@ -18,6 +18,9 @@
package org.apache.ambari.server.state.kerberos;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -181,6 +184,18 @@ public abstract class AbstractKerberosDescriptor {
return root;
}
+ public static <T> Collection<T> nullToEmpty(Collection<T> collection) {
+ return collection == null ? Collections.<T>emptyList() : collection;
+ }
+
+ public static <T> List<T> nullToEmpty(List<T> list) {
+ return list == null ? Collections.<T>emptyList() : list;
+ }
+
+ public static <K,V> Map<K,V> nullToEmpty(Map<K,V> collection) {
+ return collection == null ? Collections.<K,V>emptyMap() : collection;
+ }
+
@Override
public int hashCode() {
return 37 *
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptor.java
index 768a17e..41d1f65 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosComponentDescriptor.java
@@ -17,7 +17,9 @@
*/
package org.apache.ambari.server.state.kerberos;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.Map;
/**
@@ -111,6 +113,19 @@ public class KerberosComponentDescriptor extends AbstractKerberosDescriptorConta
return null;
}
+ /**
+ * @return identities which are not references to other identities
+ */
+ public List<KerberosIdentityDescriptor> getIdentitiesSkipReferences() {
+ List<KerberosIdentityDescriptor> result = new ArrayList<>();
+ for (KerberosIdentityDescriptor each : nullToEmpty(getIdentities())) {
+ if (!each.getReferencedServiceName().isPresent() && each.getName() != null && !each.getName().startsWith("/")) {
+ result.add(each);
+ }
+ }
+ return result;
+ }
+
@Override
public int hashCode() {
return 35 * super.hashCode();
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
index f9dfa4a..eba1b3a 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosDescriptor.java
@@ -461,12 +461,4 @@ public class KerberosDescriptor extends AbstractKerberosDescriptorContainer {
}
}
}
-
- private static <T> Collection<T> nullToEmpty(Collection<T> collection) {
- return collection == null ? Collections.<T>emptyList() : collection;
- }
-
- private static <K,V> Map<K,V> nullToEmpty(Map<K,V> collection) {
- return collection == null ? Collections.<K,V>emptyMap() : collection;
- }
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java
index e180f7a..2023793 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosIdentityDescriptor.java
@@ -17,8 +17,10 @@
*/
package org.apache.ambari.server.state.kerberos;
+import java.util.List;
import java.util.Map;
+import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.collections.Predicate;
import org.apache.ambari.server.collections.PredicateUtils;
@@ -369,6 +371,34 @@ public class KerberosIdentityDescriptor extends AbstractKerberosDescriptor {
}
}
+ /**
+ * @return true if this identity either has the same principal or keytab as any of the given identities.
+ */
+ public boolean isShared(List<KerberosIdentityDescriptor> identities) throws AmbariException {
+ for (KerberosIdentityDescriptor each : identities) {
+ if (hasSamePrincipal(each) || hasSameKeytab(each)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasSameKeytab(KerberosIdentityDescriptor that) {
+ try {
+ return this.getKeytabDescriptor().getFile().equals(that.getKeytabDescriptor().getFile());
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
+ private boolean hasSamePrincipal(KerberosIdentityDescriptor that) {
+ try {
+ return this.getPrincipalDescriptor().getValue().equals(that.getPrincipalDescriptor().getValue());
+ } catch (NullPointerException e) {
+ return false;
+ }
+ }
+
@Override
public int hashCode() {
return super.hashCode() +
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
index 8507bfa..0777327 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/state/kerberos/KerberosServiceDescriptor.java
@@ -272,6 +272,12 @@ public class KerberosServiceDescriptor extends AbstractKerberosDescriptorContain
return map;
}
+ public List<KerberosIdentityDescriptor> getComponentIdentities(String componentName) {
+ return getComponent(componentName) != null
+ ? nullToEmpty(getComponent(componentName).getIdentities())
+ : Collections.<KerberosIdentityDescriptor>emptyList();
+ }
+
@Override
public int hashCode() {
return super.hashCode() +
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
new file mode 100644
index 0000000..d22c92e
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/utilities/KerberosIdentityCleanerTest.java
@@ -0,0 +1,204 @@
+/*
+ * 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.ambari.server.controller.utilities;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.reset;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.ambari.server.controller.KerberosHelper;
+import org.apache.ambari.server.events.ServiceComponentUninstalledEvent;
+import org.apache.ambari.server.events.publishers.AmbariEventPublisher;
+import org.apache.ambari.server.serveraction.kerberos.Component;
+import org.apache.ambari.server.serveraction.kerberos.KerberosMissingAdminCredentialsException;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.SecurityType;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
+import org.easymock.EasyMockRule;
+import org.easymock.EasyMockSupport;
+import org.easymock.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class KerberosIdentityCleanerTest extends EasyMockSupport {
+ @Rule public EasyMockRule mocks = new EasyMockRule(this);
+ private static final String HOST = "c6401";
+ private static final String OOZIE = "OOZIE";
+ private static final String OOZIE_SERVER = "OOZIE_SERVER";
+ private static final String OOZIE_2 = "OOZIE2";
+ private static final String OOZIE_SERVER_2 = "OOZIE_SERVER2";
+ private static final String YARN_2 = "YARN2";
+ private static final String RESOURCE_MANAGER_2 = "RESOURCE_MANAGER2";
+ private static final String YARN = "YARN";
+ private static final String RESOURCE_MANAGER = "RESOURCE_MANAGER";
+ private static final long CLUSTER_ID = 1;
+ @Mock private KerberosHelper kerberosHelper;
+ @Mock private Clusters clusters;
+ @Mock private Cluster cluster;
+ private Map<String, Service> installedServices = new HashMap<>();
+ private KerberosDescriptorFactory kerberosDescriptorFactory = new KerberosDescriptorFactory();
+ private KerberosIdentityCleaner kerberosIdentityCleaner;
+ private KerberosDescriptor kerberosDescriptor;
+
+ @Test
+ public void removesAllKerberosIdentitesOfComponentAfterComponentWasUninstalled() throws Exception {
+ installComponent(OOZIE, OOZIE_SERVER);
+ kerberosHelper.deleteIdentity(cluster, new Component(HOST, OOZIE, OOZIE_SERVER), newArrayList("oozie_server1", "oozie_server2"));
+ expectLastCall().once();
+ replayAll();
+ uninstallComponent(OOZIE, OOZIE_SERVER, HOST);
+ verifyAll();
+ }
+
+ @Test
+ public void skipsRemovingIdentityWhenServiceDoesNotExist() throws Exception {
+ replayAll();
+ uninstallComponent("NO_SUCH_SERVICE", OOZIE_SERVER, HOST);
+ verifyAll();
+ }
+
+ @Test
+ public void skipsRemovingIdentityThatIsSharedByPrincipalName() throws Exception {
+ installComponent(OOZIE, OOZIE_SERVER);
+ installComponent(OOZIE_2, OOZIE_SERVER_2);
+ kerberosHelper.deleteIdentity(cluster, new Component(HOST, OOZIE, OOZIE_SERVER), newArrayList("oozie_server1"));
+ expectLastCall().once();
+ replayAll();
+ uninstallComponent(OOZIE, OOZIE_SERVER, HOST);
+ verifyAll();
+ }
+
+ @Test
+ public void skipsRemovingIdentityThatIsSharedByKeyTabFilePath() throws Exception {
+ installComponent(YARN, RESOURCE_MANAGER);
+ installComponent(YARN_2, RESOURCE_MANAGER_2);
+ kerberosHelper.deleteIdentity(cluster, new Component(HOST, YARN, RESOURCE_MANAGER), newArrayList("rm_unique"));
+ expectLastCall().once();
+ replayAll();
+ uninstallComponent(YARN, RESOURCE_MANAGER, HOST);
+ verifyAll();
+ }
+
+ @Test
+ public void skipsRemovingIdentityWhenClusterIsNotKerberized() throws Exception {
+ reset(cluster);
+ expect(cluster.getSecurityType()).andReturn(SecurityType.NONE).anyTimes();
+ replayAll();
+ uninstallComponent(OOZIE, OOZIE_SERVER, HOST);
+ verifyAll();
+ }
+
+ private void installComponent(String serviceName, final String componentName) {
+ Service service = createMock(serviceName + "_" + componentName, Service.class);
+ installedServices.put(serviceName, service);
+ expect(service.getServiceComponents()).andReturn(new HashMap<String, ServiceComponent>() {{
+ put(componentName, null);
+ }}).anyTimes();
+ }
+
+ private void uninstallComponent(String service, String component, String host) throws KerberosMissingAdminCredentialsException {
+ kerberosIdentityCleaner.componentRemoved(new ServiceComponentUninstalledEvent(CLUSTER_ID, "any", "any", service, component, host, false));
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ kerberosIdentityCleaner = new KerberosIdentityCleaner(new AmbariEventPublisher(), kerberosHelper, clusters);
+ kerberosDescriptor = kerberosDescriptorFactory.createInstance("{" +
+ " 'services': [" +
+ " {" +
+ " 'name': 'OOZIE'," +
+ " 'components': [" +
+ " {" +
+ " 'name': 'OOZIE_SERVER'," +
+ " 'identities': [" +
+ " {" +
+ " 'name': '/HDFS/NAMENODE/hdfs'" +
+ " }," +
+ " {" +
+ " 'name': 'oozie_server1'" +
+ " }," +"" +
+ " {" +
+ " 'name': 'oozie_server2'," +
+ " 'principal': { 'value': 'oozie/_HOST@EXAMPLE.COM' }" +
+ " }" +
+ " ]" +
+ " }" +
+ " ]" +
+ " }," +
+ " {" +
+ " 'name': 'OOZIE2'," +
+ " 'components': [" +
+ " {" +
+ " 'name': 'OOZIE_SERVER2'," +
+ " 'identities': [" +
+ " {" +
+ " 'name': 'oozie_server3'," +
+ " 'principal': { 'value': 'oozie/_HOST@EXAMPLE.COM' }" +
+ " }" +"" +
+ " ]" +
+ " }" +
+ " ]" +
+ " }," +
+ " {" +
+ " 'name': 'YARN'," +
+ " 'components': [" +
+ " {" +
+ " 'name': 'RESOURCE_MANAGER'," +
+ " 'identities': [" +
+ " {" +
+ " 'name': 'rm_unique'" +
+ " }," +
+ " {" +
+ " 'name': 'rm1-shared'," +
+ " 'keytab' : { 'file' : 'shared' }" +
+ " }" +
+ " ]" +
+ " }" +
+ " ]" +
+ " }," +
+ " {" +
+ " 'name': 'YARN2'," +
+ " 'components': [" +
+ " {" +
+ " 'name': 'RESOURCE_MANAGER2'," +
+ " 'identities': [" +
+ " {" +
+ " 'name': 'rm2-shared'," +
+ " 'keytab' : { 'file' : 'shared' }" +
+ " }" +
+ " ]" +
+ " }" +
+ " ]" +
+ " }" +
+ " ]" +
+ "}");
+ expect(clusters.getCluster(CLUSTER_ID)).andReturn(cluster).anyTimes();
+ expect(cluster.getSecurityType()).andReturn(SecurityType.KERBEROS).anyTimes();
+ expect(kerberosHelper.getKerberosDescriptor(cluster)).andReturn(kerberosDescriptor).anyTimes();
+ expect(cluster.getServices()).andReturn(installedServices).anyTimes();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/8b5c7db6/ambari-web/app/controllers/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js
index 37713dc..197eb8e 100644
--- a/ambari-web/app/controllers/main/service/item.js
+++ b/ambari-web/app/controllers/main/service/item.js
@@ -1388,8 +1388,10 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
this._super();
}
});
- self.set('deleteServiceProgressPopup', progressPopup);
- self.deleteServiceCall(serviceNames);
+ App.get('router.mainAdminKerberosController').getKDCSessionState(function() {
+ self.set('deleteServiceProgressPopup', progressPopup);
+ self.deleteServiceCall(serviceNames);
+ });
this._super();
},