You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by js...@apache.org on 2014/12/17 21:08:52 UTC
[1/2] ambari git commit: AMBARI-8700. Create orchestrator to manage
enabling and disabling Kerberos on a cluster
Repository: ambari
Updated Branches:
refs/heads/trunk 191232e29 -> ef341466e
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
index 9dd967a..eb14c20 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerTest.java
@@ -9353,6 +9353,7 @@ public class AmbariManagementControllerTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getServices
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -9396,6 +9397,7 @@ public class AmbariManagementControllerTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getServices
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -9454,6 +9456,7 @@ public class AmbariManagementControllerTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getServices
expect(clusters.getCluster("cluster1")).andReturn(cluster).times(4);
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/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
new file mode 100644
index 0000000..8804550
--- /dev/null
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java
@@ -0,0 +1,350 @@
+/*
+ * 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 com.google.inject.AbstractModule;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.actionmanager.HostRoleCommand;
+import org.apache.ambari.server.actionmanager.RequestFactory;
+import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.actionmanager.StageFactory;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.controller.internal.RequestStageContainer;
+import org.apache.ambari.server.metadata.RoleCommandOrder;
+import org.apache.ambari.server.orm.DBAccessor;
+import org.apache.ambari.server.security.SecurityHelper;
+import org.apache.ambari.server.serveraction.kerberos.KerberosCredential;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.SecurityState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponent;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.cluster.ClusterFactory;
+import org.apache.ambari.server.state.cluster.ClustersImpl;
+import org.apache.ambari.server.state.host.HostFactory;
+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.KerberosKeytabDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import org.apache.ambari.server.state.stack.OsFamily;
+import org.easymock.EasyMockSupport;
+import org.easymock.IAnswer;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.persistence.EntityManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.easymock.EasyMock.*;
+
+public class KerberosHelperTest extends EasyMockSupport {
+
+ private static Injector injector;
+
+ @Before
+ public void setUp() throws Exception {
+ injector = Guice.createInjector(new AbstractModule() {
+
+ @Override
+ protected void configure() {
+ bind(EntityManager.class).toInstance(createNiceMock(EntityManager.class));
+ bind(DBAccessor.class).toInstance(createNiceMock(DBAccessor.class));
+ bind(ClusterFactory.class).toInstance(createNiceMock(ClusterFactory.class));
+ bind(HostFactory.class).toInstance(createNiceMock(HostFactory.class));
+ bind(SecurityHelper.class).toInstance(createNiceMock(SecurityHelper.class));
+ bind(OsFamily.class).toInstance(createNiceMock(OsFamily.class));
+ bind(AmbariCustomCommandExecutionHelper.class).toInstance(createNiceMock(AmbariCustomCommandExecutionHelper.class));
+ bind(MaintenanceStateHelper.class).toInstance(createNiceMock(MaintenanceStateHelper.class));
+ bind(AmbariManagementController.class).toInstance(createNiceMock(AmbariManagementController.class));
+ bind(AmbariMetaInfo.class).toInstance(createNiceMock(AmbariMetaInfo.class));
+ bind(ActionManager.class).toInstance(createNiceMock(ActionManager.class));
+ bind(RequestFactory.class).toInstance(createNiceMock(RequestFactory.class));
+ bind(StageFactory.class).toInstance(createNiceMock(StageFactory.class));
+ bind(Clusters.class).toInstance(createNiceMock(ClustersImpl.class));
+ bind(ConfigHelper.class).toInstance(createNiceMock(ConfigHelper.class));
+ }
+ });
+ }
+
+ @After
+ public void tearDown() throws Exception {
+
+ }
+
+ @Test(expected = AmbariException.class)
+ public void testMissingClusterEnv() throws Exception {
+ KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
+
+ Cluster cluster = createNiceMock(Cluster.class);
+ KerberosDescriptor kerberosDescriptor = createNiceMock(KerberosDescriptor.class);
+ RequestStageContainer requestStageContainer = createNiceMock(RequestStageContainer.class);
+
+ replayAll();
+ kerberosHelper.toggleKerberos(cluster, kerberosDescriptor, requestStageContainer);
+ verifyAll();
+ }
+
+ @Test(expected = AmbariException.class)
+ public void testMissingKrb5Conf() throws Exception {
+ KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
+
+ final Map<String, String> clusterEnvProperties = createNiceMock(Map.class);
+ expect(clusterEnvProperties.get("security_enabled")).andReturn("true").once();
+ expect(clusterEnvProperties.get("kerberos_domain")).andReturn("FOOBAR.COM").once();
+
+ final Config clusterEnvConfig = createNiceMock(Config.class);
+ expect(clusterEnvConfig.getProperties()).andReturn(clusterEnvProperties).once();
+
+ final Cluster cluster = createNiceMock(Cluster.class);
+ expect(cluster.getDesiredConfigByType("cluster-env")).andReturn(clusterEnvConfig).once();
+
+ final KerberosDescriptor kerberosDescriptor = createNiceMock(KerberosDescriptor.class);
+
+ replayAll();
+ kerberosHelper.toggleKerberos(cluster, kerberosDescriptor, null);
+ verifyAll();
+ }
+
+ @Test
+ public void testEnableKerberos() throws Exception {
+ KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class);
+
+ final ServiceComponentHost sch1 = createNiceMock(ServiceComponentHost.class);
+ expect(sch1.getServiceName()).andReturn("SERVICE1").once();
+ expect(sch1.getServiceComponentName()).andReturn("COMPONENT1").once();
+ expect(sch1.getSecurityState()).andReturn(SecurityState.UNSECURED).anyTimes();
+
+ final ServiceComponentHost sch2 = createNiceMock(ServiceComponentHost.class);
+ expect(sch2.getServiceName()).andReturn("SERVICE2").once();
+ expect(sch2.getServiceComponentName()).andReturn("COMPONENT2").once();
+ expect(sch2.getSecurityState()).andReturn(SecurityState.UNSECURED).anyTimes();
+
+ final Host host = createNiceMock(Host.class);
+ expect(host.getHostName()).andReturn("host1").once();
+ expect(host.getState()).andReturn(HostState.HEALTHY).once();
+
+ final Service service1 = createStrictMock(Service.class);
+ expect(service1.getName()).andReturn("SERVICE1").anyTimes();
+ expect(service1.getServiceComponents())
+ .andReturn(Collections.<String, ServiceComponent>emptyMap())
+ .once();
+ service1.setSecurityState(SecurityState.SECURED_KERBEROS);
+ expectLastCall().once();
+
+ final Service service2 = createStrictMock(Service.class);
+ expect(service2.getName()).andReturn("SERVICE2").anyTimes();
+ expect(service2.getServiceComponents())
+ .andReturn(Collections.<String, ServiceComponent>emptyMap())
+ .once();
+ service2.setSecurityState(SecurityState.SECURED_KERBEROS);
+ expectLastCall().once();
+
+ final Map<String, String> clusterEnvProperties = createNiceMock(Map.class);
+ expect(clusterEnvProperties.get("security_enabled")).andReturn("true").once();
+ expect(clusterEnvProperties.get("kerberos_domain")).andReturn("FOOBAR.COM").once();
+
+ final Config clusterEnvConfig = createNiceMock(Config.class);
+ expect(clusterEnvConfig.getProperties()).andReturn(clusterEnvProperties).once();
+
+ final Map<String, String> krb5ConfProperties = createNiceMock(Map.class);
+ expect(krb5ConfProperties.get("kdc_type")).andReturn("mit-kdc").once();
+
+ final Config krb5ConfConfig = createNiceMock(Config.class);
+ expect(krb5ConfConfig.getProperties()).andReturn(krb5ConfProperties).once();
+
+ final MaintenanceStateHelper maintenanceStateHelper = injector.getInstance(MaintenanceStateHelper.class);
+ expect(maintenanceStateHelper.getEffectiveState(anyObject(ServiceComponentHost.class)))
+ .andReturn(MaintenanceState.OFF).anyTimes();
+
+ final Cluster cluster = createNiceMock(Cluster.class);
+ expect(cluster.getDesiredConfigByType("cluster-env")).andReturn(clusterEnvConfig).once();
+ expect(cluster.getDesiredConfigByType("krb5-conf")).andReturn(krb5ConfConfig).once();
+ expect(cluster.getClusterName()).andReturn("c1").anyTimes();
+ expect(cluster.getServices())
+ .andReturn(new HashMap<String, Service>() {
+ {
+ put("SERVICE1", service1);
+ put("SERVICE2", service2);
+ }
+ })
+ .anyTimes();
+ expect(cluster.getServiceComponentHosts("host1"))
+ .andReturn(new ArrayList<ServiceComponentHost>() {
+ {
+ add(sch1);
+ add(sch2);
+ }
+ })
+ .once();
+ expect(cluster.getCurrentStackVersion())
+ .andReturn(new StackId("HDP", "2.2"))
+ .anyTimes();
+ expect(cluster.getSessionAttributes()).andReturn(new HashMap<String, Object>(){{
+ put("kerberos_admin/" + KerberosCredential.KEY_NAME_PRINCIPAL, "principal");
+ put("kerberos_admin/" + KerberosCredential.KEY_NAME_PASSWORD, "password");
+ put("kerberos_admin/" + KerberosCredential.KEY_NAME_KEYTAB, "keytab");
+ }}).anyTimes();
+
+ final Clusters clusters = injector.getInstance(Clusters.class);
+ expect(clusters.getHostsForCluster("c1"))
+ .andReturn(new HashMap<String, Host>() {
+ {
+ put("host1", host);
+ }
+ })
+ .once();
+
+ final AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
+ expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, "host1"))
+ .andReturn(Collections.<String, Map<String, String>>emptyMap())
+ .once();
+ expect(ambariManagementController.getRoleCommandOrder(cluster))
+ .andReturn(createNiceMock(RoleCommandOrder.class))
+ .once();
+
+ final ConfigHelper configHelper = injector.getInstance(ConfigHelper.class);
+ expect(configHelper.getEffectiveConfigProperties(anyObject(Cluster.class), anyObject(Map.class)))
+ .andReturn(new HashMap<String, Map<String, String>>() {
+ {
+ put("cluster-env", new HashMap<String, String>() {{
+ put("kerberos_domain", "FOOBAR.COM");
+ }});
+ }
+ })
+ .once();
+ expect(configHelper.getEffectiveConfigAttributes(anyObject(Cluster.class), anyObject(Map.class)))
+ .andReturn(Collections.<String, Map<String, Map<String, String>>>emptyMap())
+ .once();
+
+ final KerberosPrincipalDescriptor principalDescriptor1 = createNiceMock(KerberosPrincipalDescriptor.class);
+ expect(principalDescriptor1.getValue()).andReturn("component1/_HOST@${realm").once();
+ expect(principalDescriptor1.getConfiguration()).andReturn("service1-site/component1.kerberos.principal").once();
+
+ final KerberosPrincipalDescriptor principalDescriptor2 = createNiceMock(KerberosPrincipalDescriptor.class);
+ expect(principalDescriptor2.getValue()).andReturn("component2/_HOST@${realm").once();
+ expect(principalDescriptor2.getConfiguration()).andReturn("service2-site/component2.kerberos.principal").once();
+
+ final KerberosKeytabDescriptor keytabDescriptor1 = createNiceMock(KerberosKeytabDescriptor.class);
+ expect(keytabDescriptor1.getFile()).andReturn("${keytab_dir}/service1.keytab").once();
+ expect(keytabDescriptor1.getOwnerName()).andReturn("service1").once();
+ expect(keytabDescriptor1.getOwnerAccess()).andReturn("rw").once();
+ expect(keytabDescriptor1.getGroupName()).andReturn("hadoop").once();
+ expect(keytabDescriptor1.getGroupAccess()).andReturn("").once();
+ expect(keytabDescriptor1.getConfiguration()).andReturn("service1-site/component1.keytab.file").once();
+
+ final KerberosKeytabDescriptor keytabDescriptor2 = createNiceMock(KerberosKeytabDescriptor.class);
+ expect(keytabDescriptor2.getFile()).andReturn("${keytab_dir}/service2.keytab").once();
+ expect(keytabDescriptor2.getOwnerName()).andReturn("service2").once();
+ expect(keytabDescriptor2.getOwnerAccess()).andReturn("rw").once();
+ expect(keytabDescriptor2.getGroupName()).andReturn("hadoop").once();
+ expect(keytabDescriptor2.getGroupAccess()).andReturn("").once();
+ expect(keytabDescriptor2.getConfiguration()).andReturn("service2-site/component2.keytab.file").once();
+
+ final KerberosIdentityDescriptor identityDescriptor1 = createNiceMock(KerberosIdentityDescriptor.class);
+ expect(identityDescriptor1.getPrincipalDescriptor()).andReturn(principalDescriptor1).once();
+ expect(identityDescriptor1.getKeytabDescriptor()).andReturn(keytabDescriptor1).once();
+
+ final KerberosIdentityDescriptor identityDescriptor2 = createNiceMock(KerberosIdentityDescriptor.class);
+ expect(identityDescriptor2.getPrincipalDescriptor()).andReturn(principalDescriptor2).once();
+ expect(identityDescriptor2.getKeytabDescriptor()).andReturn(keytabDescriptor2).once();
+
+ final KerberosComponentDescriptor componentDescriptor1 = createNiceMock(KerberosComponentDescriptor.class);
+ expect(componentDescriptor1.getIdentities(true)).
+ andReturn(new ArrayList<KerberosIdentityDescriptor>() {{
+ add(identityDescriptor1);
+ }}).once();
+
+ final KerberosComponentDescriptor componentDescriptor2 = createNiceMock(KerberosComponentDescriptor.class);
+ expect(componentDescriptor2.getIdentities(true)).
+ andReturn(new ArrayList<KerberosIdentityDescriptor>() {{
+ add(identityDescriptor2);
+ }}).once();
+
+ final KerberosServiceDescriptor serviceDescriptor1 = createNiceMock(KerberosServiceDescriptor.class);
+ expect(serviceDescriptor1.getComponent("COMPONENT1")).andReturn(componentDescriptor1).once();
+
+ final KerberosServiceDescriptor serviceDescriptor2 = createNiceMock(KerberosServiceDescriptor.class);
+ expect(serviceDescriptor2.getComponent("COMPONENT2")).andReturn(componentDescriptor2).once();
+
+ final KerberosDescriptor kerberosDescriptor = createNiceMock(KerberosDescriptor.class);
+ expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once();
+ expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once();
+
+ final StageFactory stageFactory = injector.getInstance(StageFactory.class);
+ expect(stageFactory.createNew(anyLong(), anyObject(String.class), anyObject(String.class),
+ anyLong(), anyObject(String.class), anyObject(String.class), anyObject(String.class),
+ anyObject(String.class)))
+ .andAnswer(new IAnswer<Stage>() {
+ @Override
+ public Stage answer() throws Throwable {
+ Stage stage = createNiceMock(Stage.class);
+
+ expect(stage.getHostRoleCommands())
+ .andReturn(Collections.<String, Map<String, HostRoleCommand>>emptyMap())
+ .anyTimes();
+ replay(stage);
+ return stage;
+ }
+ })
+ .anyTimes();
+
+ // This is a STRICT mock to help ensure that the end result is what we want.
+ final RequestStageContainer requestStageContainer = createStrictMock(RequestStageContainer.class);
+ // Create Principals Stage
+ expect(requestStageContainer.getId()).andReturn(1L).once();
+ requestStageContainer.addStages(anyObject(List.class));
+ expectLastCall().once();
+ // Create Keytabs Stage
+ expect(requestStageContainer.getId()).andReturn(1L).once();
+ requestStageContainer.addStages(anyObject(List.class));
+ expectLastCall().once();
+ // TODO: Add more of these when more stages are added.
+ // Clean-up/Finalize Stage
+ expect(requestStageContainer.getId()).andReturn(1L).once();
+ requestStageContainer.addStages(anyObject(List.class));
+ expectLastCall().once();
+
+ replayAll();
+
+ // Needed by infrastructure
+ injector.getInstance(AmbariMetaInfo.class).init();
+
+ kerberosHelper.toggleKerberos(cluster, kerberosDescriptor, requestStageContainer);
+
+ verifyAll();
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
index a66add3..5fb2831 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/ComponentResourceProviderTest.java
@@ -53,6 +53,7 @@ import org.apache.ambari.server.StackAccessException;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
+import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.MaintenanceStateHelper;
import org.apache.ambari.server.controller.RequestStatusResponse;
import org.apache.ambari.server.controller.ServiceComponentRequest;
@@ -798,6 +799,7 @@ public class ComponentResourceProviderTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getComponents
expect(clusters.getCluster("cluster1")).andReturn(cluster);
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
index 2e80e24..a00afce 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostResourceProviderTest.java
@@ -26,6 +26,7 @@ import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.controller.AmbariManagementControllerImpl;
import org.apache.ambari.server.controller.HostResponse;
+import org.apache.ambari.server.controller.KerberosHelper;
import org.apache.ambari.server.controller.MaintenanceStateHelper;
import org.apache.ambari.server.controller.RequestStatusResponse;
import org.apache.ambari.server.controller.HostRequest;
@@ -957,6 +958,7 @@ public class HostResourceProviderTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHosts
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -1006,6 +1008,7 @@ public class HostResourceProviderTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHosts
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -1054,6 +1057,7 @@ public class HostResourceProviderTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHosts
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -1118,6 +1122,7 @@ public class HostResourceProviderTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHosts
expect(clusters.getCluster("cluster1")).andReturn(cluster).times(4);
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java
index fd1017b..d720da2 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/serveraction/kerberos/KerberosServerActionTest.java
@@ -45,7 +45,6 @@ import static org.mockito.Mockito.when;
public class KerberosServerActionTest {
-
Map<String, String> commandParams = new HashMap<String, String>();
File temporaryDirectory;
private Injector injector;
@@ -110,7 +109,6 @@ public class KerberosServerActionTest {
}
builder.close();
-
commandParams.put(KerberosServerAction.DATA_DIRECTORY, temporaryDirectory.getAbsolutePath());
commandParams.put(KerberosServerAction.DEFAULT_REALM, "REALM.COM");
commandParams.put(KerberosServerAction.KDC_TYPE, KDCType.MIT_KDC.toString());
[2/2] ambari git commit: AMBARI-8700. Create orchestrator to manage
enabling and disabling Kerberos on a cluster
Posted by js...@apache.org.
AMBARI-8700. Create orchestrator to manage enabling and disabling Kerberos on a cluster
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ef341466
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ef341466
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ef341466
Branch: refs/heads/trunk
Commit: ef341466e49d8f7f2cc144bb63416fb25a77f6d3
Parents: 191232e
Author: Robert Levas <rl...@hortonworks.com>
Authored: Wed Dec 17 15:07:38 2014 -0500
Committer: John Speidel <js...@hortonworks.com>
Committed: Wed Dec 17 15:08:43 2014 -0500
----------------------------------------------------------------------
.../AmbariManagementControllerImpl.java | 24 +-
.../server/controller/ClusterRequest.java | 31 +-
.../server/controller/KerberosHelper.java | 1117 ++++++++++++++++++
.../internal/ClusterResourceProvider.java | 114 ++
.../kerberos/FinalizeKerberosServerAction.java | 94 ++
.../kerberos/KerberosServerAction.java | 137 ++-
.../AmbariManagementControllerImplTest.java | 17 +
.../AmbariManagementControllerTest.java | 3 +
.../server/controller/KerberosHelperTest.java | 350 ++++++
.../internal/ComponentResourceProviderTest.java | 2 +
.../internal/HostResourceProviderTest.java | 5 +
.../kerberos/KerberosServerActionTest.java | 2 -
12 files changed, 1828 insertions(+), 68 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
index 435c828..f58fa9d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/AmbariManagementControllerImpl.java
@@ -207,6 +207,11 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
private MaintenanceStateHelper maintenanceStateHelper;
+ /**
+ * The KerberosHelper to help setup for enabling for disabling Kerberos
+ */
+ private KerberosHelper kerberosHelper;
+
final private String masterHostname;
final private Integer masterPort;
final private String masterProtocol;
@@ -246,7 +251,7 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
LOG.info("Initializing the AmbariManagementControllerImpl");
masterHostname = InetAddress.getLocalHost().getCanonicalHostName();
maintenanceStateHelper = injector.getInstance(MaintenanceStateHelper.class);
-
+ kerberosHelper = injector.getInstance(KerberosHelper.class);
if(configs != null)
{
if (configs.getApiSSLAuthentication()) {
@@ -1316,7 +1321,22 @@ public class AmbariManagementControllerImpl implements AmbariManagementControlle
saveClusterUpdate(request, clusterResponse);
}
- return null;
+ RequestStageContainer requestStageContainer = null;
+ Map<String, Service> services = cluster.getServices();
+ if ((services != null) && services.containsKey("KERBEROS")) {
+ // Handle either adding or removing Kerberos from the cluster. This may generate multiple stages
+ // or not depending the current state of the cluster. The main configuration used to determine
+ // whether Kerberos is to be added or removed is cluster-config/security_enabled.
+ requestStageContainer = kerberosHelper.toggleKerberos(cluster,
+ request.getKerberosDescriptor(), null);
+ }
+
+ if (requestStageContainer != null) {
+ requestStageContainer.persist();
+ return requestStageContainer.getRequestStatusResponse();
+ } else {
+ return null;
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
index 5dd0be0..8d2cce1 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/ClusterRequest.java
@@ -18,6 +18,8 @@
package org.apache.ambari.server.controller;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -42,6 +44,11 @@ public class ClusterRequest {
private ServiceConfigVersionRequest serviceConfigVersionRequest = null;
/**
+ * A KerberosDescriptor parsed from the request payload.
+ */
+ private KerberosDescriptor kerberosDescriptor;
+
+ /**
* The cluster session attributes.
*/
private final Map<String, Object> sessionAttributes;
@@ -56,12 +63,13 @@ public class ClusterRequest {
public ClusterRequest(Long clusterId, String clusterName,
String provisioningState, String stackVersion, Set<String> hostNames) {
- this(clusterId, clusterName, provisioningState, stackVersion, hostNames, null);
+ this(clusterId, clusterName, provisioningState, stackVersion, hostNames, null, null);
}
public ClusterRequest(Long clusterId, String clusterName,
String provisioningState, String stackVersion,
- Set<String> hostNames, Map<String, Object> sessionAttributes) {
+ Set<String> hostNames, KerberosDescriptor kerberosDescriptor,
+ Map<String, Object> sessionAttributes) {
super();
this.clusterId = clusterId;
this.clusterName = clusterName;
@@ -69,6 +77,7 @@ public class ClusterRequest {
this.stackVersion = stackVersion;
this.hostNames = hostNames;
this.sessionAttributes = sessionAttributes;
+ this.kerberosDescriptor = kerberosDescriptor;
}
@@ -165,6 +174,24 @@ public class ClusterRequest {
return configs;
}
+ /**
+ * Returns the KerberosDescriptor for this ClusterRequest
+ *
+ * @return a KerberosDescriptor or null if one was not specified
+ */
+ public KerberosDescriptor getKerberosDescriptor() {
+ return kerberosDescriptor;
+ }
+
+ /**
+ * Sets a KerberosDescriptor for this ClusterRequest
+ *
+ * @param kerberosDescriptor a KerberosDescriptor
+ */
+ public void setKerberosDescriptor(KerberosDescriptor kerberosDescriptor) {
+ this.kerberosDescriptor = kerberosDescriptor;
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/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
new file mode 100644
index 0000000..625c0f6
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java
@@ -0,0 +1,1117 @@
+/*
+ * 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 com.google.inject.Inject;
+import com.google.inject.persist.Transactional;
+import org.apache.ambari.server.AmbariException;
+import org.apache.ambari.server.Role;
+import org.apache.ambari.server.RoleCommand;
+import org.apache.ambari.server.actionmanager.ActionManager;
+import org.apache.ambari.server.actionmanager.RequestFactory;
+import org.apache.ambari.server.actionmanager.Stage;
+import org.apache.ambari.server.actionmanager.StageFactory;
+import org.apache.ambari.server.api.services.AmbariMetaInfo;
+import org.apache.ambari.server.configuration.Configuration;
+import org.apache.ambari.server.controller.internal.RequestStageContainer;
+import org.apache.ambari.server.metadata.RoleCommandOrder;
+import org.apache.ambari.server.serveraction.ServerAction;
+import org.apache.ambari.server.serveraction.kerberos.CreateKeytabFilesServerAction;
+import org.apache.ambari.server.serveraction.kerberos.CreatePrincipalsServerAction;
+import org.apache.ambari.server.serveraction.kerberos.FinalizeKerberosServerAction;
+import org.apache.ambari.server.serveraction.kerberos.KDCType;
+import org.apache.ambari.server.serveraction.kerberos.KerberosActionDataFile;
+import org.apache.ambari.server.serveraction.kerberos.KerberosActionDataFileBuilder;
+import org.apache.ambari.server.serveraction.kerberos.KerberosConfigDataFile;
+import org.apache.ambari.server.serveraction.kerberos.KerberosConfigDataFileBuilder;
+import org.apache.ambari.server.serveraction.kerberos.KerberosCredential;
+import org.apache.ambari.server.serveraction.kerberos.KerberosServerAction;
+import org.apache.ambari.server.stageplanner.RoleGraph;
+import org.apache.ambari.server.state.Cluster;
+import org.apache.ambari.server.state.Clusters;
+import org.apache.ambari.server.state.Config;
+import org.apache.ambari.server.state.ConfigHelper;
+import org.apache.ambari.server.state.Host;
+import org.apache.ambari.server.state.HostState;
+import org.apache.ambari.server.state.MaintenanceState;
+import org.apache.ambari.server.state.SecurityState;
+import org.apache.ambari.server.state.Service;
+import org.apache.ambari.server.state.ServiceComponentHost;
+import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosConfigurationDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
+import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
+import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent;
+import org.apache.ambari.server.utils.StageUtils;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+public class KerberosHelper {
+ private static final String BASE_LOG_DIR = "/tmp/ambari";
+
+ private static final Logger LOG = LoggerFactory.getLogger(KerberosHelper.class);
+
+ @Inject
+ private AmbariCustomCommandExecutionHelper customCommandExecutionHelper;
+
+ @Inject
+ private MaintenanceStateHelper maintenanceStateHelper;
+
+ @Inject
+ private AmbariManagementController ambariManagementController;
+
+ @Inject
+ private AmbariMetaInfo ambariMetaInfo;
+
+ @Inject
+ private ActionManager actionManager;
+
+ @Inject
+ private RequestFactory requestFactory;
+
+ @Inject
+ private StageFactory stageFactory;
+
+ @Inject
+ private Clusters clusters;
+
+ @Inject
+ private ConfigHelper configHelper;
+
+ /**
+ * The Handler implementation that provides the logic to enable Kerberos
+ */
+ private Handler enableKerberosHandler = new EnableKerberosHandler();
+
+ /**
+ * The Handler implementation that provides the logic to disable Kerberos
+ */
+ private Handler disableKerberosHandler = new DisableKerberosHandler();
+
+
+ /**
+ * Toggles Kerberos security to enable it or remove it depending on the state of the cluster.
+ * <p/>
+ * The "cluster-env" configuration set is used to determine the security state of the cluster.
+ * If the "security_enabled" property is set to "true" than an attempt will be make to enable
+ * Kerberos; if "false" an attempt will be made to disable Kerberos.
+ * Also, the "kerberos_domain" is used as the default Kerberos realm for the cluster.
+ * <p/>
+ * The "krb5-conf" configuration type ios used to obtain information about the relevant KDC.
+ * The "kdc_type" property is used to determine what type of KDC is being used so that the
+ * appropriate actions maybe taken in order interact with it properly.
+ * <p/>
+ * This process is idempotent such that it may be called several times, each time only affecting
+ * items that need to be brought up to date.
+ *
+ * @param cluster the relevant Cluster
+ * @param kerberosDescriptor a KerberosDescriptor containing updates to the descriptor already
+ * configured for the cluster
+ * @param requestStageContainer a RequestStageContainer to place generated stages, if needed -
+ * if null a new RequestStageContainer will be created.
+ * @return the updated or a new RequestStageContainer containing the stages that need to be
+ * executed to complete this task; or null if no stages need to be executed.
+ * @throws AmbariException
+ */
+ public RequestStageContainer toggleKerberos(Cluster cluster, KerberosDescriptor kerberosDescriptor,
+ RequestStageContainer requestStageContainer)
+ throws AmbariException {
+
+ if (cluster == null) {
+ String message = "The cluster object is not available";
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+
+ Config configClusterEnv = cluster.getDesiredConfigByType("cluster-env");
+ if (configClusterEnv == null) {
+ String message = "The 'cluster-env' configuration is not available";
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+
+ Map<String, String> clusterEnvProperties = configClusterEnv.getProperties();
+ if (clusterEnvProperties == null) {
+ String message = "The 'cluster-env' configuration properties are not available";
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+
+ String securityEnabled = clusterEnvProperties.get("security_enabled");
+ if ((securityEnabled == null) || securityEnabled.isEmpty()) {
+ LOG.warn("Missing 'securityEnabled' property of cluster-env, unable to determine the cluster's security state. This may be ok.");
+ } else {
+ String defaultRealm = clusterEnvProperties.get("kerberos_domain");
+
+ Config configKrb5Conf = cluster.getDesiredConfigByType("krb5-conf");
+ if (configKrb5Conf == null) {
+ String message = "The 'krb5-conf' configuration is not available";
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+
+ Map<String, String> krb5ConfProperties = configKrb5Conf.getProperties();
+ if (krb5ConfProperties == null) {
+ String message = "The 'krb5-conf' configuration properties are not available";
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+
+ KDCType kdcType = null;
+ String kdcTypeProperty = krb5ConfProperties.get("kdc_type");
+ if (kdcTypeProperty != null) {
+ try {
+ kdcType = KDCType.translate(kdcTypeProperty);
+ } catch (IllegalArgumentException e) {
+ String message = String.format("Invalid 'kdc_type' value: %s", kdcTypeProperty);
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+ }
+
+ if (kdcType == null) {
+ // Set the KDCType to the the MIT_KDC as a fallback.
+ kdcType = KDCType.MIT_KDC;
+ }
+
+ if ("true".equalsIgnoreCase(securityEnabled)) {
+ LOG.info("Configuring Kerberos for realm {} on cluster, {}", defaultRealm, cluster.getClusterName());
+ requestStageContainer = handle(cluster, kerberosDescriptor, defaultRealm, kdcType, requestStageContainer, enableKerberosHandler);
+ } else if ("false".equalsIgnoreCase(securityEnabled)) {
+ LOG.info("Disabling Kerberos from cluster, {}", cluster.getClusterName());
+ requestStageContainer = handle(cluster, kerberosDescriptor, defaultRealm, kdcType, requestStageContainer, disableKerberosHandler);
+ } else {
+ String message = String.format("Invalid value for `security_enabled` property of cluster-env: %s", securityEnabled);
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+ }
+
+ return requestStageContainer;
+ }
+
+ /**
+ * Performs operations needed to enable to disable Kerberos on the relevant cluster.
+ * <p/>
+ * Iterates through the components installed on the relevant cluster and attempts to enable or
+ * disable Kerberos as needed.
+ * <p/>
+ * The supplied Handler instance handles the logic on whether this process enables or disables
+ * Kerberos.
+ *
+ * @param cluster the relevant Cluster
+ * @param kerberosDescriptor the (derived) KerberosDescriptor
+ * @param realm the default Kerberos realm for the Cluster
+ * @param kdcType the relevant KDC type (MIT KDC or Active Directory)
+ * @param requestStageContainer a RequestStageContainer to place generated stages, if needed -
+ * if null a new RequestStageContainer will be created.
+ * @return the updated or a new RequestStageContainer containing the stages that need to be
+ * executed to complete this task; or null if no stages need to be executed.
+ * @throws AmbariException
+ */
+ @Transactional
+ private RequestStageContainer handle(Cluster cluster,
+ KerberosDescriptor kerberosDescriptor,
+ String realm, KDCType kdcType,
+ RequestStageContainer requestStageContainer,
+ Handler handler) throws AmbariException {
+
+ Map<String, Service> services = cluster.getServices();
+
+ if ((services != null) && !services.isEmpty()) {
+ SecurityState desiredSecurityState = handler.getNewServiceSecurityState();
+ String clusterName = cluster.getClusterName();
+ Map<String, Host> hosts = clusters.getHostsForCluster(clusterName);
+
+ if ((hosts != null) && !hosts.isEmpty()) {
+ List<ServiceComponentHost> serviceComponentHostsToProcess = new ArrayList<ServiceComponentHost>();
+ File indexFile;
+ kerberosDescriptor = buildKerberosDescriptor(cluster.getCurrentStackVersion(), kerberosDescriptor);
+ KerberosActionDataFileBuilder kerberosActionDataFileBuilder = null;
+ Map<String, String> kerberosDescriptorProperties = kerberosDescriptor.getProperties();
+ Map<String, Map<String, String>> kerberosConfigurations = new HashMap<String, Map<String, String>>();
+
+ // Create a temporary directory to store metadata needed to complete this task. Information
+ // such as which principals and keytabs files to create as well as what configurations need
+ // to be update are stored in data files in this directory. Any keytab files are stored in
+ // this directory until they are distributed to their appropriate hosts.
+ File dataDirectory;
+ try {
+ dataDirectory = createTemporaryDirectory();
+ } catch (IOException e) {
+ String message = "Failed to create the temporary data directory.";
+ LOG.error(message, e);
+ throw new AmbariException(message, e);
+ }
+
+ // Create the file used to store details about principals and keytabs to create
+ indexFile = new File(dataDirectory, KerberosActionDataFile.DATA_FILE_NAME);
+
+ try {
+ // Iterate over the hosts in the cluster to find the components installed in each. For each
+ // component (aka service component host - sch) determine the configuration updates and
+ // and the principals an keytabs to create.
+ for (Host host : hosts.values()) {
+ // Only process "healthy" hosts. When an unhealthy host becomes healthy, it will be
+ // processed the next time this executes.
+ if (host.getState() == HostState.HEALTHY) {
+ String hostname = host.getHostName();
+
+ // Get a list of components on the current host
+ List<ServiceComponentHost> serviceComponentHosts = cluster.getServiceComponentHosts(hostname);
+
+ if ((serviceComponentHosts != null) && !serviceComponentHosts.isEmpty()) {
+ // Calculate the current host-specific configurations. These will be used to replace
+ // variables within the Kerberos descriptor data
+ Map<String, Map<String, String>> configurations = calculateConfigurations(cluster, hostname);
+
+ // If any properties are set in the calculated KerberosDescriptor, add them into the
+ // Map of configurations as an un-categorized type (using an empty string)
+ if (kerberosDescriptorProperties != null) {
+ if (configurations == null) {
+ configurations = new HashMap<String, Map<String, String>>();
+ }
+
+ if (configurations.get("") == null) {
+ configurations.put("", kerberosDescriptorProperties);
+ } else {
+ configurations.get("").putAll(kerberosDescriptorProperties);
+ }
+ }
+
+ // 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 : serviceComponentHosts) {
+ String serviceName = sch.getServiceName();
+ KerberosServiceDescriptor serviceDescriptor = kerberosDescriptor.getService(serviceName);
+
+ if (serviceDescriptor != null) {
+ KerberosComponentDescriptor componentDescriptor = serviceDescriptor.getComponent(sch.getServiceComponentName());
+
+ if (componentDescriptor != null) {
+ int identitiesAdded = 0;
+ // Test to see if this component should be process by querying the handler
+ if (handler.shouldProcess(desiredSecurityState, sch)) {
+ // Calculate the set of configurations to update and replace any variables
+ // using the previously calculated Map of configurations for the host.
+ mergeConfigurations(kerberosConfigurations,
+ componentDescriptor.getConfigurations(true), configurations);
+
+ // Lazily create the KerberosActionDataFileBuilder instance...
+ if (kerberosActionDataFileBuilder == null) {
+ kerberosActionDataFileBuilder = new KerberosActionDataFileBuilder(indexFile);
+ }
+
+ // Add service-level principals (and keytabs)
+ identitiesAdded += addIdentities(kerberosActionDataFileBuilder,
+ serviceDescriptor.getIdentities(true), sch, configurations);
+
+ // Add component-level principals (and keytabs)
+ identitiesAdded += addIdentities(kerberosActionDataFileBuilder,
+ componentDescriptor.getIdentities(true), sch, configurations);
+
+ if (identitiesAdded > 0) {
+ serviceComponentHostsToProcess.add(sch);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (IOException e) {
+ String message = String.format("Failed to write index file - %s", indexFile.getAbsolutePath());
+ LOG.error(message);
+ throw new AmbariException(message, e);
+ } finally {
+ if (kerberosActionDataFileBuilder != null) {
+ // Make sure the data file is closed
+ try {
+ kerberosActionDataFileBuilder.close();
+ } catch (IOException e) {
+ LOG.warn("Failed to close the index file writer", e);
+ }
+ }
+ }
+
+ // If there are ServiceComponentHosts to process, make sure the administrator credentials
+ // are available
+ if (!serviceComponentHostsToProcess.isEmpty()) {
+ if (getEncryptedAdministratorCredentials(cluster) == null) {
+ try {
+ FileUtils.deleteDirectory(dataDirectory);
+ } catch (IOException e) {
+ LOG.warn(String.format("The data directory (%s) was not deleted due to an error condition - {%s}",
+ dataDirectory.getAbsolutePath(), e.getMessage()), e);
+ }
+ throw new AmbariException("Missing KDC administrator credentials");
+ }
+ }
+
+ // Always set up the necessary stages to perform the tasks needed to complete the operation.
+ // Some stages may be no-ops, this is expected.
+ // Gather data needed to create stages and tasks...
+ Map<String, Set<String>> clusterHostInfo = StageUtils.getClusterHostInfo(hosts, cluster);
+ String clusterHostInfoJson = StageUtils.getGson().toJson(clusterHostInfo);
+ Map<String, String> hostParams = customCommandExecutionHelper.createDefaultHostParams(cluster);
+ String hostParamsJson = StageUtils.getGson().toJson(hostParams);
+ String ambariServerHostname = StageUtils.getHostName();
+ ServiceComponentHostServerActionEvent event = new ServiceComponentHostServerActionEvent(
+ "AMBARI_SERVER",
+ ambariServerHostname, // TODO: Choose a random hostname from the cluster. All tasks for the AMBARI_SERVER service will be executed on this Ambari server
+ System.currentTimeMillis());
+ RoleCommandOrder roleCommandOrder = ambariManagementController.getRoleCommandOrder(cluster);
+
+ // If a RequestStageContainer does not already exist, create a new one...
+ if (requestStageContainer == null) {
+ requestStageContainer = new RequestStageContainer(
+ actionManager.getNextRequestId(),
+ null,
+ requestFactory,
+ actionManager);
+ }
+
+ // Use the handler implementation to setup the relevant stages.
+ int lastStageId = handler.createStages(cluster, hosts, kerberosConfigurations,
+ clusterHostInfoJson, hostParamsJson, event, roleCommandOrder, realm, kdcType.toString(),
+ dataDirectory, requestStageContainer);
+
+ // Add the cleanup stage...
+
+ Map<String, String> commandParameters = new HashMap<String, String>();
+ commandParameters.put(KerberosServerAction.DATA_DIRECTORY, dataDirectory.getAbsolutePath());
+
+ Stage stage = createServerActionStage(++lastStageId,
+ cluster,
+ requestStageContainer.getId(),
+ "Finalize Operations",
+ clusterHostInfoJson,
+ "{}",
+ hostParamsJson,
+ FinalizeKerberosServerAction.class,
+ event,
+ commandParameters,
+ 300);
+
+ RoleGraph roleGraph = new RoleGraph(roleCommandOrder);
+ roleGraph.build(stage);
+ requestStageContainer.addStages(roleGraph.getStages());
+
+ // If all goes well, set the appropriate states on the relevant ServiceComponentHosts
+ for (ServiceComponentHost sch : serviceComponentHostsToProcess) {
+ // Update the desired and current states for the ServiceComponentHost
+ // using new state information from the the handler implementation
+ sch.setDesiredSecurityState(handler.getNewDesiredSCHSecurityState());
+ sch.setSecurityState(handler.getNewSCHSecurityState());
+ }
+ }
+
+ // If all goes well, set all services to _desire_ to be secured or unsecured, depending on handler
+ for (Service service : services.values()) {
+ service.setSecurityState(desiredSecurityState);
+ }
+ }
+
+ return requestStageContainer;
+ }
+
+ /**
+ * Creates a temporary directory within the system temporary directory
+ * <p/>
+ * The resulting directory is to be removed by the caller when desired.
+ *
+ * @return a File pointing to the new temporary directory, or null if one was not created
+ * @throws java.io.IOException if a new temporary directory cannot be created
+ */
+ private File createTemporaryDirectory() throws IOException {
+ String tempDirectoryPath = System.getProperty("java.io.tmpdir");
+ if (tempDirectoryPath == null) {
+ throw new IOException("The System property 'java.io.tmpdir' does not specify a temporary directory");
+ }
+
+ File directory;
+ int tries = 0;
+ long now = System.currentTimeMillis();
+
+ do {
+ directory = new File(tempDirectoryPath, String.format("%s%d-%d.d",
+ KerberosServerAction.DATA_DIRECTORY_PREFIX, now, tries));
+
+ if ((directory.exists()) || !directory.mkdirs()) {
+ directory = null; // Rest and try again...
+ } else {
+ LOG.debug("Created temporary directory: {}", directory.getAbsolutePath());
+ }
+ } while ((directory == null) && (++tries < 100));
+
+ if (directory == null) {
+ throw new IOException(String.format("Failed to create a temporary directory in %s", tempDirectoryPath));
+ }
+
+ return directory;
+ }
+
+ /**
+ * Build a composite Kerberos descriptor using the default descriptor data, existing cluster
+ * descriptor data (future), and the supplied descriptor updates from the request
+ *
+ * @param currentStackVersion the current cluster's StackId
+ * @param kerberosDescriptor a KerberosDescriptor containing updates from the request payload
+ * @return a KerberosDescriptor containing existing data with requested changes
+ * @throws AmbariException
+ */
+ private KerberosDescriptor buildKerberosDescriptor(StackId currentStackVersion,
+ KerberosDescriptor kerberosDescriptor)
+ throws AmbariException {
+ KerberosDescriptor defaultKerberosDescriptor = ambariMetaInfo.getKerberosDescriptor(
+ currentStackVersion.getStackName(),
+ currentStackVersion.getStackVersion()
+ );
+
+ if (defaultKerberosDescriptor == null) {
+ return kerberosDescriptor;
+ } else {
+ if (kerberosDescriptor != null) {
+ defaultKerberosDescriptor.update(kerberosDescriptor);
+ }
+ return defaultKerberosDescriptor;
+ }
+ }
+
+ /**
+ * Merges configuration from a Map of configuration updates into a main configurations Map. Each
+ * property in the updates Map is processed to replace variables using the replacement Map.
+ * <p/>
+ * See {@link org.apache.ambari.server.state.kerberos.KerberosDescriptor#replaceVariables(String, java.util.Map)}
+ * for information on variable replacement.
+ *
+ * @param configurations a Map of configurations
+ * @param updates a Map of configuration updates
+ * @param replacements a Map of (grouped) replacement values
+ * @return the merged Map
+ * @throws AmbariException
+ */
+ private Map<String, Map<String, String>> mergeConfigurations(Map<String, Map<String, String>> configurations,
+ Map<String, KerberosConfigurationDescriptor> updates,
+ Map<String, Map<String, String>> replacements)
+ throws AmbariException {
+
+ if ((updates != null) && !updates.isEmpty()) {
+ if (configurations == null) {
+ configurations = new HashMap<String, Map<String, String>>();
+ }
+
+ for (Map.Entry<String, KerberosConfigurationDescriptor> entry : updates.entrySet()) {
+ String type = entry.getKey();
+ KerberosConfigurationDescriptor configurationDescriptor = entry.getValue();
+
+ if (configurationDescriptor != null) {
+ Map<String, String> updatedProperties = configurationDescriptor.getProperties();
+
+ if (updatedProperties != null) {
+ Map<String, String> existingProperties = configurations.get(type);
+ if (existingProperties == null) {
+ existingProperties = new HashMap<String, String>();
+ configurations.put(type, existingProperties);
+ }
+
+ for (Map.Entry<String, String> property : updatedProperties.entrySet()) {
+ existingProperties.put(property.getKey(),
+ KerberosDescriptor.replaceVariables(property.getValue(), replacements));
+ }
+ }
+ }
+ }
+ }
+
+ return configurations;
+ }
+
+ /**
+ * Adds identities to the KerberosActionDataFileBuilder.
+ *
+ * @param kerberosActionDataFileBuilder a KerberosActionDataFileBuilder to use for storing identity
+ * records
+ * @param identities a List of KerberosIdentityDescriptors to add to the data
+ * file
+ * @param sch the relevant ServiceComponentHost
+ * @param configurations a Map of configurations to use a replacements for variables
+ * in identity fields
+ * @return an integer indicating the number of identities added to the data file
+ * @throws java.io.IOException if an error occurs while writing a record to the data file
+ */
+ private int addIdentities(KerberosActionDataFileBuilder kerberosActionDataFileBuilder,
+ List<KerberosIdentityDescriptor> identities,
+ ServiceComponentHost sch,
+ Map<String, Map<String, String>> configurations) throws IOException {
+ int identitiesAdded = 0;
+
+ if (identities != null) {
+ for (KerberosIdentityDescriptor identity : identities) {
+ KerberosPrincipalDescriptor principalDescriptor = identity.getPrincipalDescriptor();
+ String principal = null;
+ String principalConfiguration = null;
+
+ if (principalDescriptor != null) {
+ principal = KerberosDescriptor.replaceVariables(principalDescriptor.getValue(), configurations);
+ principalConfiguration = KerberosDescriptor.replaceVariables(principalDescriptor.getConfiguration(), configurations);
+ }
+
+ if (principal != null) {
+ KerberosKeytabDescriptor keytabDescriptor = identity.getKeytabDescriptor();
+ String keytabFilePath = null;
+ String keytabFileOwnerName = null;
+ String keytabFileOwnerAccess = null;
+ String keytabFileGroupName = null;
+ String keytabFileGroupAccess = null;
+ String keytabFileConfiguration = null;
+
+ if (keytabDescriptor != null) {
+ keytabFilePath = KerberosDescriptor.replaceVariables(keytabDescriptor.getFile(), configurations);
+ keytabFileOwnerName = KerberosDescriptor.replaceVariables(keytabDescriptor.getOwnerName(), configurations);
+ keytabFileOwnerAccess = KerberosDescriptor.replaceVariables(keytabDescriptor.getOwnerAccess(), configurations);
+ keytabFileGroupName = KerberosDescriptor.replaceVariables(keytabDescriptor.getGroupName(), configurations);
+ keytabFileGroupAccess = KerberosDescriptor.replaceVariables(keytabDescriptor.getGroupAccess(), configurations);
+ keytabFileConfiguration = KerberosDescriptor.replaceVariables(keytabDescriptor.getConfiguration(), configurations);
+ }
+
+ kerberosActionDataFileBuilder.addRecord(sch.getHostName(),
+ sch.getServiceName(),
+ sch.getServiceComponentName(),
+ principal,
+ principalConfiguration,
+ keytabFilePath,
+ keytabFileOwnerName,
+ keytabFileOwnerAccess,
+ keytabFileGroupName,
+ keytabFileGroupAccess,
+ keytabFileConfiguration);
+
+ identitiesAdded++;
+ }
+ }
+ }
+
+ return identitiesAdded;
+ }
+
+ /**
+ * Calculates the map of configurations relative to the cluster and host.
+ * <p/>
+ * This was borrowed from {@link org.apache.ambari.server.actionmanager.ExecutionCommandWrapper#getExecutionCommand()}
+ *
+ * @param cluster the relevant Cluster
+ * @param hostname the relevant hostname
+ * @return a Map of calculated configuration types
+ * @throws AmbariException
+ */
+ private Map<String, Map<String, String>> calculateConfigurations(Cluster cluster, String hostname) throws AmbariException {
+ // For a configuration type, both tag and an actual configuration can be stored
+ // Configurations from the tag is always expanded and then over-written by the actual
+ // global:version1:{a1:A1,b1:B1,d1:D1} + global:{a1:A2,c1:C1,DELETED_d1:x} ==>
+ // global:{a1:A2,b1:B1,c1:C1}
+ Map<String, Map<String, String>> configurations = new HashMap<String, Map<String, String>>();
+
+ Map<String, Map<String, String>> configurationTags = ambariManagementController.findConfigurationTagsWithOverrides(cluster, hostname);
+ Map<String, Map<String, Map<String, String>>> configurationAttributes = new TreeMap<String, Map<String, Map<String, String>>>();
+
+ if (configurationTags.get(Configuration.GLOBAL_CONFIG_TAG) != null) {
+ configHelper.applyCustomConfig(
+ configurations, Configuration.GLOBAL_CONFIG_TAG,
+ Configuration.RCA_ENABLED_PROPERTY, "false", false);
+ }
+
+ Map<String, Map<String, String>> configProperties = configHelper.getEffectiveConfigProperties(cluster, configurationTags);
+
+ // Apply the configurations saved with the Execution Cmd on top of
+ // derived configs - This will take care of all the hacks
+ for (Map.Entry<String, Map<String, String>> entry : configProperties.entrySet()) {
+ String type = entry.getKey();
+ Map<String, String> allLevelMergedConfig = entry.getValue();
+ Map<String, String> configuration = configurations.get(type);
+
+ if (configuration == null) {
+ configuration = new HashMap<String, String>(allLevelMergedConfig);
+ } else {
+ Map<String, String> mergedConfig = configHelper.getMergedConfig(allLevelMergedConfig, configuration);
+ configuration.clear();
+ configuration.putAll(mergedConfig);
+ }
+
+ configurations.put(type, configuration);
+ }
+
+ Map<String, Map<String, Map<String, String>>> configAttributes =
+ configHelper.getEffectiveConfigAttributes(cluster, configurationTags);
+
+ for (Map.Entry<String, Map<String, Map<String, String>>> attributesOccurrence : configAttributes.entrySet()) {
+ String type = attributesOccurrence.getKey();
+ Map<String, Map<String, String>> attributes = attributesOccurrence.getValue();
+
+ if (!configurationAttributes.containsKey(type)) {
+ configurationAttributes.put(type, new TreeMap<String, Map<String, String>>());
+ }
+ configHelper.cloneAttributesMap(attributes, configurationAttributes.get(type));
+ }
+
+ return configurations;
+ }
+
+ /**
+ * Creates a new stage
+ *
+ * @param id the new stage's id
+ * @param cluster the relevant Cluster
+ * @param requestId the relevant request Id
+ * @param requestContext a String describing the stage
+ * @param clusterHostInfo JSON-encoded clusterHostInfo structure
+ * @param commandParams JSON-encoded command parameters
+ * @param hostParams JSON-encoded host parameters
+ * @return a newly created Stage
+ */
+ private Stage createNewStage(long id, Cluster cluster, long requestId,
+ String requestContext, String clusterHostInfo,
+ String commandParams, String hostParams) {
+ Stage stage = stageFactory.createNew(requestId,
+ BASE_LOG_DIR + File.pathSeparator + requestId,
+ cluster.getClusterName(),
+ cluster.getClusterId(),
+ requestContext,
+ clusterHostInfo,
+ commandParams,
+ hostParams);
+
+ stage.setStageId(id);
+ return stage;
+ }
+
+ /**
+ * Creates a new stage with a single task describing the ServerAction class to invoke and the other
+ * task-related information.
+ *
+ * @param id the new stage's id
+ * @param cluster the relevant Cluster
+ * @param requestId the relevant request Id
+ * @param requestContext a String describing the stage
+ * @param clusterHostInfo JSON-encoded clusterHostInfo structure
+ * @param commandParams JSON-encoded command parameters
+ * @param hostParams JSON-encoded host parameters
+ * @param actionClass The ServeAction class that implements the action to invoke
+ * @param event The relevant ServiceComponentHostServerActionEvent
+ * @param commandParameters a Map of command parameters to attach to the task added to the new
+ * stage
+ * @param timeout the timeout for the task/action
+ * @return a newly created Stage
+ */
+ private Stage createServerActionStage(long id, Cluster cluster, long requestId,
+ String requestContext, String clusterHostInfo,
+ String commandParams, String hostParams,
+ Class<? extends ServerAction> actionClass,
+ ServiceComponentHostServerActionEvent event,
+ Map<String, String> commandParameters, Integer timeout) {
+
+ Stage stage = createNewStage(id, cluster, requestId, requestContext, clusterHostInfo, commandParams, hostParams);
+ stage.addServerActionCommand(actionClass.getName(),
+ Role.AMBARI_SERVER_ACTION,
+ RoleCommand.EXECUTE,
+ cluster.getClusterName(),
+ event,
+ commandParameters,
+ timeout);
+
+ return stage;
+ }
+
+ /**
+ * Using the session data from the relevant Cluster object, creates a KerberosCredential,
+ * serializes, and than encrypts it.
+ * <p/>
+ * Since the relevant data is stored in the HTTPSession (which relies on ThreadLocalStorage),
+ * it needs to be retrieved now and placed in the action's command parameters so it will be
+ * available when needed. Because command parameters are stored in plaintext in the Ambari database,
+ * this (sensitive) data needs to be encrypted, however it needs to be done using a key the can be
+ * recreated sometime later when the data needs to be access. Since it is expected that the Cluster
+ * object will be able now and later, the hashcode of this object is used to build the key - it
+ * is expected that the same instance will be retrieved from the Clusters instance, thus yielding
+ * the same hashcode value.
+ * <p/>
+ * If the Ambari server architecture changes, this will need to be revisited.
+ *
+ * @param cluster the relevant Cluster
+ * @return a serialized and encrypted KerberosCredential, or null if administrator data is not found
+ * @throws AmbariException
+ */
+ private String getEncryptedAdministratorCredentials(Cluster cluster) throws AmbariException {
+ String encryptedAdministratorCredentials = null;
+
+ Map<String, Object> sessionAttributes = cluster.getSessionAttributes();
+ if (sessionAttributes != null) {
+ KerberosCredential credential = KerberosCredential.fromMap(sessionAttributes, "kerberos_admin/");
+ if (credential != null) {
+ byte[] key = Integer.toHexString(cluster.hashCode()).getBytes();
+ encryptedAdministratorCredentials = credential.encrypt(key);
+ }
+ }
+
+ return encryptedAdministratorCredentials;
+ }
+
+ /**
+ * Handler is an interface that needs to be implemented by toggle handler classes to do the
+ * "right" thing for the task at hand.
+ */
+ private interface Handler {
+ /**
+ * Tests the Service and ServiceComponentHost to see if they are in the appropriate security
+ * state to be processed for the relevant task.
+ *
+ * @param desiredSecurityState the SecurityState to be transitioned to
+ * @param sch the ServiceComponentHost to test
+ * @return true if both the Service and ServiceComponentHost are in the appropriate security
+ * state to be processed; otherwise false
+ * @throws AmbariException of an error occurs while testing
+ */
+ boolean shouldProcess(SecurityState desiredSecurityState, ServiceComponentHost sch) throws AmbariException;
+
+ /**
+ * Returns the new SecurityState to be set as the ServiceComponentHost's _desired_ SecurityState.
+ *
+ * @return a SecurityState to be set as the ServiceComponentHost's _desired_ SecurityState
+ */
+ SecurityState getNewDesiredSCHSecurityState();
+
+ /**
+ * Returns the new SecurityState to be set as the ServiceComponentHost's _current_ SecurityState.
+ *
+ * @return a SecurityState to be set as the ServiceComponentHost's _current_ SecurityState
+ */
+ SecurityState getNewSCHSecurityState();
+
+
+ /**
+ * Returns the new SecurityState to be set as the Service's SecurityState.
+ *
+ * @return a SecurityState to be set as the Service's SecurityState
+ */
+ SecurityState getNewServiceSecurityState();
+
+ /**
+ * Creates the necessary stages to complete the relevant task and stores them in the supplied
+ * or a newly created RequestStageContainer.
+ * <p/>
+ * If the supplied RequestStageContainer is null, a new one must be created and filled.
+ * {@link org.apache.ambari.server.controller.internal.RequestStageContainer#persist()} should
+ * not be called since it is not known if the set of states for this container is complete.
+ *
+ * @param cluster the relevant Cluster
+ * @param hosts the relevant Map of Hosts
+ * @param kerberosConfigurations the compiled KerberosConfigurations for the entire Kerberos
+ * descriptor hierarchy with all variables replaced
+ * @param clusterHostInfo JSON-encoded clusterHostInfo structure
+ * @param hostParams JSON-encoded host parameters
+ * @param event a ServiceComponentHostServerActionEvent to pass to any created tasks
+ * @param roleCommandOrder the RoleCommandOrder to use to generate the RoleGraph for any newly created Stages
+ * @param realm a String declaring the cluster's Kerberos realm
+ * @param kdcType a relevant KDCType
+ * @param dataDirectory a File pointing to the (temporary) data directory
+ * @param requestStageContainer a RequestStageContainer to store the new stages in, if null a
+ * new RequestStageContainer will be created
+ * @return the last stage id generated, or -1 if no stages were created
+ * @throws AmbariException if an error occurs while creating the relevant stages
+ */
+ int createStages(Cluster cluster, Map<String, Host> hosts,
+ Map<String, Map<String, String>> kerberosConfigurations,
+ String clusterHostInfo, String hostParams,
+ ServiceComponentHostServerActionEvent event,
+ RoleCommandOrder roleCommandOrder,
+ String realm, String kdcType, File dataDirectory,
+ RequestStageContainer requestStageContainer)
+ throws AmbariException;
+
+ }
+
+ /**
+ * EnableKerberosHandler is an implementation of the Handler interface used to enable Kerberos
+ * on the relevant cluster
+ * <p/>
+ * This implementation attempts to set the Service and ServiceComponentHost _desired_ security
+ * states to {@link org.apache.ambari.server.state.SecurityState#SECURED_KERBEROS} and the
+ * ServiceComponentHost _current_ security state to {@link org.apache.ambari.server.state.SecurityState#SECURING}.
+ * <p/>
+ * To complete the process, this implementation creates the following stages:
+ * <ol>
+ * <li>create principals</li>
+ * <li>create keytab files</li>
+ * <li>distribute keytab files to the appropriate hosts</li>
+ * <li>update relevant configurations</li>
+ * <li>restart services</li>
+ * </ol>
+ */
+ private class EnableKerberosHandler implements Handler {
+ @Override
+ public boolean shouldProcess(SecurityState desiredSecurityState, ServiceComponentHost sch) throws AmbariException {
+ return (desiredSecurityState == SecurityState.SECURED_KERBEROS) &&
+ (maintenanceStateHelper.getEffectiveState(sch) == MaintenanceState.OFF) &&
+ (sch.getSecurityState() != SecurityState.SECURED_KERBEROS) &&
+ (sch.getSecurityState() != SecurityState.SECURING);
+ }
+
+ @Override
+ public SecurityState getNewDesiredSCHSecurityState() {
+ return SecurityState.SECURED_KERBEROS;
+ }
+
+ @Override
+ public SecurityState getNewSCHSecurityState() {
+ // TODO (rlevas): Set this to SecurityState.SECURING
+ // when the required infrastructure is in place
+ // See AMBARI-8343 and associated JIRAs (like AMBARI-8477)
+ return SecurityState.SECURED_KERBEROS;
+ }
+
+ @Override
+ public SecurityState getNewServiceSecurityState() {
+ return SecurityState.SECURED_KERBEROS;
+ }
+
+ @Override
+ public int createStages(Cluster cluster, Map<String, Host> hosts,
+ Map<String, Map<String, String>> kerberosConfigurations,
+ String clusterHostInfoJson, String hostParamsJson,
+ ServiceComponentHostServerActionEvent event,
+ RoleCommandOrder roleCommandOrder, String realm, String kdcType,
+ File dataDirectory, RequestStageContainer requestStageContainer) throws AmbariException {
+ // If there are principals, keytabs, and configurations to process, setup the following sages:
+ // 1) generate principals
+ // 2) generate keytab files
+ // 3) distribute keytab files
+ // 4) update configurations
+ // 4) restart services
+
+ RoleGraph roleGraph;
+ Stage stage;
+ int stageId = -1;
+
+ // If a RequestStageContainer does not already exist, create a new one...
+ if (requestStageContainer == null) {
+ requestStageContainer = new RequestStageContainer(
+ actionManager.getNextRequestId(),
+ null,
+ requestFactory,
+ actionManager);
+ }
+
+ // If there are configurations to set, create a (temporary) data file to store the configuration
+ // updates and fill it will the relevant configurations.
+ if (!kerberosConfigurations.isEmpty()) {
+ File configFile = new File(dataDirectory, KerberosConfigDataFile.DATA_FILE_NAME);
+ KerberosConfigDataFileBuilder kerberosConfDataFileBuilder = null;
+ try {
+ kerberosConfDataFileBuilder = new KerberosConfigDataFileBuilder(configFile);
+
+ for (Map.Entry<String, Map<String, String>> entry : kerberosConfigurations.entrySet()) {
+ String type = entry.getKey();
+ Map<String, String> properties = entry.getValue();
+
+ if (properties != null) {
+ for (Map.Entry<String, String> configTypeEntry : properties.entrySet()) {
+ kerberosConfDataFileBuilder.addRecord(type,
+ configTypeEntry.getKey(),
+ configTypeEntry.getValue());
+ }
+ }
+ }
+ } catch (IOException e) {
+ String message = String.format("Failed to write kerberos configurations file - %s", configFile.getAbsolutePath());
+ LOG.error(message);
+ throw new AmbariException(message, e);
+ } finally {
+ if (kerberosConfDataFileBuilder != null) {
+ try {
+ kerberosConfDataFileBuilder.close();
+ } catch (IOException e) {
+ LOG.warn("Failed to close the kerberos configurations file writer", e);
+ }
+ }
+ }
+ }
+
+ Map<String, String> commandParameters = new HashMap<String, String>();
+ commandParameters.put(KerberosServerAction.DATA_DIRECTORY, dataDirectory.getAbsolutePath());
+ commandParameters.put(KerberosServerAction.DEFAULT_REALM, realm);
+ commandParameters.put(KerberosServerAction.KDC_TYPE, kdcType);
+ commandParameters.put(KerberosServerAction.ADMINISTRATOR_CREDENTIAL, getEncryptedAdministratorCredentials(cluster));
+
+ // *****************************************************************
+ // Create stage to create principals
+ stage = createServerActionStage(++stageId,
+ cluster,
+ requestStageContainer.getId(),
+ "Create Principals",
+ clusterHostInfoJson,
+ "{}",
+ hostParamsJson,
+ CreatePrincipalsServerAction.class,
+ event,
+ commandParameters,
+ 1200);
+
+ roleGraph = new RoleGraph(roleCommandOrder);
+ roleGraph.build(stage);
+ requestStageContainer.addStages(roleGraph.getStages());
+
+ // *****************************************************************
+ // Create stage to generate keytabs
+ stage = createServerActionStage(++stageId,
+ cluster,
+ requestStageContainer.getId(),
+ "Create Keytabs",
+ clusterHostInfoJson,
+ "{}",
+ hostParamsJson,
+ CreateKeytabFilesServerAction.class,
+ event,
+ commandParameters,
+ 1200);
+
+ roleGraph = new RoleGraph(roleCommandOrder);
+ roleGraph.build(stage);
+ requestStageContainer.addStages(roleGraph.getStages());
+
+ // *****************************************************************
+ // Create stage to distribute keytabs
+ // TODO (dilli): Implement this
+ /*
+ stage = createServerActionStage(++stageId,
+ cluster,
+ requestStageContainer.getId(),
+ "Distribute Kerberos keytabs to services",
+ clusterHostInfoJson,
+ "{}",
+ hostParamsJson,
+ DISTRIBUTE_KEYTABS.class,
+ event,
+ commandParameters,
+ 1200);
+
+ roleGraph = new RoleGraph(roleCommandOrder);
+ roleGraph.build(stage);
+ requestStageContainer.addStages(roleGraph.getStages());
+ */
+
+ // *****************************************************************
+ // Create stage to update configurations
+ // TODO: (dilli): implement this
+ /*
+ stage = createServerActionStage(++stageId,
+ cluster,
+ requestStageContainer.getId(),
+ "Distribute Kerberos keytabs to services",
+ clusterHostInfoJson,
+ "{}",
+ hostParamsJson,
+ UPDATE_SERVICE_CONFIGURATIONS.class
+ event,
+ commandParameters,
+ 1200);
+
+ roleGraph = new RoleGraph(roleCommandOrder);
+ roleGraph.build(stage);
+ requestStageContainer.addStages(roleGraph.getStages());
+ */
+
+ return stageId;
+ }
+ }
+
+ /**
+ * DisableKerberosHandler is an implementation of the Handler interface used to disable Kerberos
+ * on the relevant cluster
+ * <p/>
+ * This implementation attempts to set the Service and ServiceComponentHost _desired_ security
+ * states to {@link org.apache.ambari.server.state.SecurityState#UNSECURED} and the ServiceComponentHost
+ * _current_ security state to {@link org.apache.ambari.server.state.SecurityState#UNSECURING}.
+ * <p/>
+ * To complete the process, this implementation creates the following stages:
+ * <ol>
+ * <li>update relevant configurations</li>
+ * <li>delete keytab files</li>
+ * <li>remove principals</li>
+ * <li>restart services</li>
+ * </ol>
+ */
+ private class DisableKerberosHandler implements Handler {
+ @Override
+ public boolean shouldProcess(SecurityState desiredSecurityState, ServiceComponentHost sch) throws AmbariException {
+ return (desiredSecurityState == SecurityState.UNSECURED) &&
+ (maintenanceStateHelper.getEffectiveState(sch) == MaintenanceState.OFF) &&
+ (sch.getSecurityState() != SecurityState.UNSECURED) &&
+ (sch.getSecurityState() != SecurityState.UNSECURING);
+ }
+
+ @Override
+ public SecurityState getNewDesiredSCHSecurityState() {
+ return SecurityState.UNSECURED;
+ }
+
+ @Override
+ public SecurityState getNewSCHSecurityState() {
+ // TODO (rlevas): Set this to SecurityState.UNSECURING
+ // when the required infrastructure is in place
+ // See AMBARI-8343 and associated JIRAs (like AMBARI-8477)
+ return SecurityState.UNSECURED;
+ }
+
+ @Override
+ public SecurityState getNewServiceSecurityState() {
+ return SecurityState.UNSECURED;
+ }
+
+ @Override
+ public int createStages(Cluster cluster, Map<String, Host> hosts,
+ Map<String, Map<String, String>> kerberosConfigurations,
+ String clusterHostInfoJson, String hostParamsJson,
+ ServiceComponentHostServerActionEvent event,
+ RoleCommandOrder roleCommandOrder, String realm, String kdcType,
+ File dataDirectory, RequestStageContainer requestStageContainer) {
+ // TODO (rlevas): If there are principals, keytabs, and configurations to process, setup the following sages:
+ // 1) remove principals
+ // 2) remove keytab files
+ // 3) update configurations
+ // 3) restart services
+ return -1;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
index 551698a..f9aca1d 100644
--- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
+++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/ClusterResourceProvider.java
@@ -17,6 +17,7 @@
*/
package org.apache.ambari.server.controller.internal;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -50,6 +51,7 @@ import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.ConfigImpl;
import org.apache.ambari.server.state.StackId;
+import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
/**
* Resource provider for cluster resources.
@@ -317,6 +319,14 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
baseUnsupported.remove("default_password");
baseUnsupported.remove("configurations");
+ // Allow property Ids that start with "kerberos_descriptor/"
+ Iterator<String> iterator = baseUnsupported.iterator();
+ while (iterator.hasNext()) {
+ if (iterator.next().startsWith("kerberos_descriptor/")) {
+ iterator.remove();
+ }
+ }
+
return checkConfigPropertyIds(baseUnsupported, "Clusters");
}
@@ -354,12 +364,15 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
* @return the cluster request object
*/
private ClusterRequest getRequest(Map<String, Object> properties) {
+ KerberosDescriptor kerberosDescriptor = new KerberosDescriptor(createKerberosPropertyMap(properties));
+
ClusterRequest cr = new ClusterRequest(
(Long) properties.get(CLUSTER_ID_PROPERTY_ID),
(String) properties.get(CLUSTER_NAME_PROPERTY_ID),
(String) properties.get(CLUSTER_PROVISIONING_STATE_PROPERTY_ID),
(String) properties.get(CLUSTER_VERSION_PROPERTY_ID),
null,
+ kerberosDescriptor,
getSessionAttributes(properties));
List<ConfigurationRequest> configRequests = getConfigurationRequests("Clusters", properties);
@@ -377,6 +390,107 @@ public class ClusterResourceProvider extends BaseBlueprintProcessor {
}
/**
+ * Recursively attempts to "normalize" a property value into either a single Object, a Map or a
+ * Collection of items depending on the type of Object that is supplied.
+ * <p/>
+ * If the supplied value is a Map, attempts to render a Map of keys to "normalized" values. This
+ * may yield a Map of Maps or a Map of Collections, or a Map of values.
+ * <p/>
+ * If the supplied value is a Collection, attempts to render a Collection of Maps, Collections, or values
+ * <p/>
+ * Else, assumes the value is a simple value
+ *
+ * @param property an Object to "normalize"
+ * @return the normalized object or the input value if it is not a Map or Collection.
+ */
+ private Object normalizeKerberosProperty(Object property) {
+ if (property instanceof Map) {
+ Map<?, ?> properties = (Map) property;
+ Map<String, Object> map = new HashMap<String, Object>(properties.size());
+
+ for (Map.Entry<?, ?> entry : properties.entrySet()) {
+ normalizeKerberosProperty(entry.getKey().toString(), entry.getValue(), map);
+ }
+
+ return map;
+ } else if (property instanceof Collection) {
+ Collection properties = (Collection) property;
+ Collection<Object> collection = new ArrayList<Object>(properties.size());
+
+ for (Object item : properties) {
+ collection.add(normalizeKerberosProperty(item));
+ }
+
+ return collection;
+ } else {
+ return property;
+ }
+ }
+
+ /**
+ * Recursively attempts to "normalize" a property value into either a single Object, a Map or a
+ * Collection of items; and places the result into the supplied Map under a specified key.
+ * <p/>
+ * See {@link #normalizeKerberosProperty(Object)} for more information "normalizing" a property value
+ *
+ * If the key (propertyName) indicates a hierarchy by separating names with a '/', the supplied map
+ * will be updated to handle the hierarchy. For example, if the propertyName value is "parent/child"
+ * then the map will be updated to contain an entry where the key is named "parent" and the value
+ * is a Map containing an entry with a name of "child" and value that is the normalized version of
+ * the specified value (propertyValue).
+ *
+ * @param propertyName a String declaring the name of the supplied property value
+ * @param propertyValue an Object containing the property value
+ * @param map a Map to store the results within
+ * @see #normalizeKerberosProperty(Object)
+ */
+ private void normalizeKerberosProperty(String propertyName, Object propertyValue, Map<String, Object> map) {
+ String[] keys = propertyName.split("/");
+ Map<String, Object> currentMap = map;
+
+ if (keys.length > 0) {
+ for (int i = 0; i < keys.length - 1; i++) {
+ String key = keys[i];
+
+ Object value = currentMap.get(key);
+
+ if (value instanceof Map) {
+ currentMap = (Map<String, Object>) value;
+ } else {
+ Map<String, Object> temp = new HashMap<String, Object>();
+ currentMap.put(key, temp);
+ currentMap = temp;
+ }
+ }
+
+ currentMap.put(keys[keys.length - 1], normalizeKerberosProperty(propertyValue));
+ }
+ }
+
+ /**
+ * Given a Map of Strings to Objects, attempts to expand all properties into a tree of Maps to
+ * effectively represent a Kerberos descriptor.
+ *
+ * @param properties a Map of properties to process
+ * @return a Map containing the expanded hierarchy of data
+ * @see #normalizeKerberosProperty(String, Object, java.util.Map)
+ */
+ private Map<String, Object> createKerberosPropertyMap(Map<String, Object> properties) {
+ Map<String, Object> kerberosPropertyMap = new HashMap<String, Object>();
+
+ if (properties != null) {
+ for (Map.Entry<String, Object> entry : properties.entrySet()) {
+ String key = entry.getKey();
+ if (key.startsWith("kerberos_descriptor/")) {
+ normalizeKerberosProperty(key.replace("kerberos_descriptor/", ""), entry.getValue(), kerberosPropertyMap);
+ }
+ }
+ }
+
+ return kerberosPropertyMap;
+ }
+
+ /**
* Get the map of session attributes from the given property map.
*
* @param properties the property map from the request
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/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
new file mode 100644
index 0000000..2c6b33e
--- /dev/null
+++ b/ambari-server/src/main/java/org/apache/ambari/server/serveraction/kerberos/FinalizeKerberosServerAction.java
@@ -0,0 +1,94 @@
+/*
+ * 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.AmbariException;
+import org.apache.ambari.server.actionmanager.HostRoleStatus;
+import org.apache.ambari.server.agent.CommandReport;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.ConcurrentMap;
+
+public class FinalizeKerberosServerAction extends KerberosServerAction {
+ private final static Logger LOG = LoggerFactory.getLogger(FinalizeKerberosServerAction.class);
+
+ /**
+ * Processes an identity as necessary.
+ * <p/>
+ * This method is not used since the {@link #processIdentities(java.util.Map)} is not invoked
+ *
+ * @param identityRecord a Map containing the data for the current identity record
+ * @param evaluatedPrincipal a String indicating the relevant principal
+ * @param operationHandler a KerberosOperationHandler used to perform Kerberos-related
+ * tasks for specific Kerberos implementations
+ * (MIT, Active Directory, etc...)
+ * @param requestSharedDataContext a Map to be used a shared data among all ServerActions related
+ * to a given request
+ * @return null, always
+ * @throws AmbariException
+ */
+ @Override
+ protected CommandReport processIdentity(Map<String, String> identityRecord, String evaluatedPrincipal,
+ KerberosOperationHandler operationHandler,
+ Map<String, Object> requestSharedDataContext)
+ throws AmbariException {
+
+ return null;
+ }
+
+ /**
+ *
+ * @param requestSharedDataContext a Map to be used a shared data among all ServerActions related
+ * to a given request
+ * @return
+ * @throws AmbariException
+ * @throws InterruptedException
+ */
+ @Override
+ public CommandReport execute(ConcurrentMap<String, Object> requestSharedDataContext) throws AmbariException, InterruptedException {
+ String dataDirectoryPath = getCommandParameterValue(DATA_DIRECTORY);
+
+ // 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.
+ LOG.warn(String.format("The data directory (%s) was not deleted due to an error condition - {%s}",
+ dataDirectory.getAbsolutePath(), e.getMessage()), e);
+ }
+ }
+ }
+
+ return createCommandReport(0, HostRoleStatus.COMPLETED, "{}", null, null); }
+}
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/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 a3a1b5b..2df1829 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
@@ -68,6 +68,12 @@ public abstract class KerberosServerAction extends AbstractServerAction {
*/
public static final String KDC_TYPE = "kdc_type";
+ /**
+ * The prefix to use for the data directory name.
+ */
+ public static final String DATA_DIRECTORY_PREFIX = ".ambari_";
+
+
/*
* Kerberos action shared data entry names
*/
@@ -180,8 +186,9 @@ public abstract class KerberosServerAction extends AbstractServerAction {
protected KerberosCredential getAdministratorCredential(Map<String, String> commandParameters) throws AmbariException {
Cluster cluster = clusters.getCluster(getExecutionCommand().getClusterName());
- if(cluster == null)
+ if (cluster == null) {
throw new AmbariException("Failed get the Cluster object");
+ }
// Create the key like we did when we encrypted the data, based on the Cluster objects hashcode.
byte[] key = Integer.toHexString(cluster.hashCode()).getBytes();
@@ -239,73 +246,79 @@ public abstract class KerberosServerAction extends AbstractServerAction {
if (dataDirectoryPath != null) {
File dataDirectory = new File(dataDirectoryPath);
- if (!dataDirectory.exists() || !dataDirectory.isDirectory()) {
- String message = String.format("Failed to process the identities, the data directory does not exist: %s",
- dataDirectory.getAbsolutePath());
- LOG.error(message);
- throw new AmbariException(message);
- }
- // The "index" file is expected to be in the specified data directory and named "index.dat"
- File indexFile = new File(dataDirectory, DATA_FILE_NAME);
-
- if (!indexFile.canRead()) {
- String message = String.format("Failed to process the identities, cannot read the index file: %s",
- indexFile.getAbsolutePath());
- LOG.error(message);
- throw new AmbariException(message);
- }
- // Create the data file reader to parse and iterate through the records
- KerberosActionDataFileReader reader = null;
- KerberosOperationHandler handler = KerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
-
- if (handler == null) {
- String message = String.format("Failed to process the identities, cannot read the index file: %s",
- indexFile.getAbsolutePath());
- LOG.error(message);
- throw new AmbariException(message);
- }
-
- handler.open(administratorCredential, defaultRealm);
-
- try {
- reader = new KerberosActionDataFileReader(indexFile);
- for (Map<String, String> record : reader) {
- // Process the current record
- commandReport = processRecord(record, defaultRealm, handler, requestSharedDataContext);
+ // If the data directory exists, attempt to process further, else assume there is no work to do
+ if (dataDirectory.exists()) {
+ if (!dataDirectory.isDirectory() || !dataDirectory.canRead()) {
+ String message = String.format("Failed to process the identities, the data directory is not accessible: %s",
+ dataDirectory.getAbsolutePath());
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
+ // The "index" file may or may not exist in the data directory, depending on if there
+ // is work to do or not.
+ File indexFile = new File(dataDirectory, DATA_FILE_NAME);
+
+ if (indexFile.exists()) {
+ if (!indexFile.canRead()) {
+ String message = String.format("Failed to process the identities, cannot read the index file: %s",
+ indexFile.getAbsolutePath());
+ LOG.error(message);
+ throw new AmbariException(message);
+ }
- // If the principal processor returns a CommandReport, than it is time to stop since
- // an error condition has probably occurred, else all is assumed to be well.
- if (commandReport != null) {
- break;
+ KerberosOperationHandler handler = KerberosOperationHandlerFactory.getKerberosOperationHandler(kdcType);
+ if (handler == null) {
+ String message = String.format("Failed to process the identities, a KDC operation handler was not found for the KDC type of : %s",
+ kdcType.toString());
+ LOG.error(message);
+ throw new AmbariException(message);
}
- }
- } catch (AmbariException e) {
- // Catch this separately from IOException since the reason it was thrown was not the same
- // Note: AmbariException is an IOException, so there may be some confusion
- throw new AmbariException(e.getMessage(), e);
- } catch (IOException e) {
- String message = String.format("Failed to process the identities, cannot read the index file: %s",
- indexFile.getAbsolutePath());
- LOG.error(message, e);
- throw new AmbariException(message, e);
- } finally {
- if (reader != null) {
- // The reader needs to be closed, if it fails to close ignore the exception since
- // there is little we can or care to do about it now.
+
+ // Create the data file reader to parse and iterate through the records
+ KerberosActionDataFileReader reader = null;
try {
- reader.close();
+ handler.open(administratorCredential, defaultRealm);
+
+ reader = new KerberosActionDataFileReader(indexFile);
+ for (Map<String, String> record : reader) {
+ // Process the current record
+ commandReport = processRecord(record, defaultRealm, handler, requestSharedDataContext);
+
+ // If the principal processor returns a CommandReport, than it is time to stop since
+ // an error condition has probably occurred, else all is assumed to be well.
+ if (commandReport != null) {
+ break;
+ }
+ }
+ } catch (AmbariException e) {
+ // Catch this separately from IOException since the reason it was thrown was not the same
+ // Note: AmbariException is an IOException, so there may be some confusion
+ throw new AmbariException(e.getMessage(), e);
} catch (IOException e) {
- // Ignore this...
+ String message = String.format("Failed to process the identities, cannot read the index file: %s",
+ indexFile.getAbsolutePath());
+ LOG.error(message, e);
+ throw new AmbariException(message, e);
+ } finally {
+ if (reader != null) {
+ // The reader needs to be closed, if it fails to close ignore the exception since
+ // there is little we can or care to do about it now.
+ try {
+ reader.close();
+ } catch (IOException e) {
+ // Ignore this...
+ }
+ }
+
+ // The KerberosOperationHandler needs to be closed, if it fails to close ignore the
+ // exception since there is little we can or care to do about it now.
+ try {
+ handler.close();
+ } catch (AmbariException e) {
+ // Ignore this...
+ }
}
}
-
- // The KerberosOperationHandler needs to be closed, if it fails to close ignore the
- // exception since there is little we can or care to do about it now.
- try {
- handler.close();
- } catch (AmbariException e) {
- // Ignore this...
- }
}
}
}
http://git-wip-us.apache.org/repos/asf/ambari/blob/ef341466/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
index 4db01b9..5208a2d 100644
--- a/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
+++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/AmbariManagementControllerImplTest.java
@@ -120,6 +120,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
//replay
replay(injector);
@@ -194,6 +195,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getCluster
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -409,6 +411,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getCluster
expect(clusters.getCluster("cluster1")).andThrow(new ClusterNotFoundException("cluster1"));
@@ -462,6 +465,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getCluster
expect(clusters.getCluster("cluster1")).andThrow(new ClusterNotFoundException("cluster1"));
@@ -507,6 +511,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
expect(clusterRequest.getClusterName()).andReturn("clusterNew").times(4);
expect(clusterRequest.getClusterId()).andReturn(1L).times(4);
expect(clusters.getClusterById(1L)).andReturn(cluster);
@@ -546,6 +551,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
expect(clusterRequest.getClusterName()).andReturn("clusterNew").times(4);
expect(clusterRequest.getClusterId()).andReturn(1L).times(4);
expect(clusters.getClusterById(1L)).andReturn(cluster);
@@ -599,6 +605,7 @@ public class AmbariManagementControllerImplTest {
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -666,6 +673,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -750,6 +758,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(stateHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
@@ -851,6 +860,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster).times(3);
@@ -955,6 +965,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster).times(3);
@@ -1061,6 +1072,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster).times(3);
@@ -1144,6 +1156,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -1198,6 +1211,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper);
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andThrow(new ClusterNotFoundException("cluster1"));
@@ -1259,6 +1273,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -1345,6 +1360,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
// getHostComponent
expect(clusters.getCluster("cluster1")).andReturn(cluster);
@@ -1429,6 +1445,7 @@ public class AmbariManagementControllerImplTest {
injector.injectMembers(capture(controllerCapture));
expect(injector.getInstance(Gson.class)).andReturn(null);
expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(maintHelper).anyTimes();
+ expect(injector.getInstance(KerberosHelper.class)).andReturn(createNiceMock(KerberosHelper.class));
replay(maintHelper, injector, clusters, serviceInfo);