AMBARI-1342. Ambari 1.7 to 2.1.x upgrade with existing Kerberos, keytab files fail to be distributed to some hosts (rlevas)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/868a15d6 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/868a15d6 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/868a15d6 Branch: refs/heads/branch-dev-patch-upgrade Commit: 868a15d65074b2c4ab8aaf653e7f8779f1124769 Parents: 22f0982 Author: Robert Levas <[email protected]> Authored: Thu Oct 15 13:42:50 2015 -0400 Committer: Robert Levas <[email protected]> Committed: Thu Oct 15 13:42:57 2015 -0400 ---------------------------------------------------------------------- .../server/controller/KerberosHelperImpl.java | 4 +- .../AmbariManagementControllerImplTest.java | 48 ++++ .../server/controller/KerberosHelperTest.java | 228 +++++++++++++++++++ 3 files changed, 277 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/868a15d6/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java index dbb59bd..bf8c519 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelperImpl.java @@ -2275,9 +2275,7 @@ public class KerberosHelperImpl implements KerberosHelper { private class EnableKerberosHandler extends Handler { @Override public boolean shouldProcess(SecurityState desiredSecurityState, ServiceComponentHost sch) throws AmbariException { - return (desiredSecurityState == SecurityState.SECURED_KERBEROS) && - (sch.getSecurityState() != SecurityState.SECURED_KERBEROS) && - (sch.getSecurityState() != SecurityState.SECURING); + return (desiredSecurityState == SecurityState.SECURED_KERBEROS); } @Override http://git-wip-us.apache.org/repos/asf/ambari/blob/868a15d6/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 dd80f46..1d9e53d 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 @@ -596,6 +596,54 @@ public class AmbariManagementControllerImplTest { } /** + * Ensure that when the cluster security type updated from KERBEROS to KERBEROS, + * KerberosHandler.toggleKerberos IS NOT invoked + */ + + @Test + public void testUpdateClustersToggleKerberosReenable() throws Exception { + // member state mocks + Capture<AmbariManagementController> controllerCapture = new Capture<AmbariManagementController>(); + Injector injector = createStrictMock(Injector.class); + Cluster cluster = createNiceMock(Cluster.class); + ActionManager actionManager = createNiceMock(ActionManager.class); + ClusterRequest clusterRequest = createNiceMock(ClusterRequest.class); + + // requests + Set<ClusterRequest> setRequests = Collections.singleton(clusterRequest); + + KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class); + // expectations + injector.injectMembers(capture(controllerCapture)); + expect(injector.getInstance(Gson.class)).andReturn(null); + expect(injector.getInstance(MaintenanceStateHelper.class)).andReturn(null); + expect(injector.getInstance(KerberosHelper.class)).andReturn(kerberosHelper); + expect(clusterRequest.getClusterId()).andReturn(1L).times(6); + expect(clusterRequest.getSecurityType()).andReturn(SecurityType.KERBEROS).anyTimes(); + expect(clusters.getClusterById(1L)).andReturn(cluster).times(2); + expect(cluster.getClusterName()).andReturn("cluster").times(2); + expect(cluster.getSecurityType()).andReturn(SecurityType.KERBEROS).anyTimes(); + + cluster.addSessionAttributes(anyObject(Map.class)); + expectLastCall().once(); + + expect(kerberosHelper.shouldExecuteCustomOperations(SecurityType.KERBEROS, null)) + .andReturn(false) + .once(); + // Note: kerberosHelper.toggleKerberos is not called + + // replay mocks + replay(actionManager, cluster, clusters, injector, clusterRequest, sessionManager, kerberosHelper); + + // test + AmbariManagementController controller = new AmbariManagementControllerImpl(actionManager, clusters, injector); + controller.updateClusters(setRequests, null); + + // assert and verify + assertSame(controller, controllerCapture.getValue()); + verify(actionManager, cluster, clusters, injector, clusterRequest, sessionManager, kerberosHelper); + } + /** * Ensure that when the cluster security type updated from NONE to KERBEROS, KerberosHandler.toggleKerberos * IS invoked */ http://git-wip-us.apache.org/repos/asf/ambari/blob/868a15d6/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java index 97e1b7e..d3f54e5 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/KerberosHelperTest.java @@ -272,6 +272,11 @@ public class KerberosHelperTest extends EasyMockSupport { } @Test + public void testEnableKerberos_UpgradeFromAmbari170KerberizedCluster() throws Exception { + testEnableKerberos_UpgradeFromAmbari170KerberizedCluster(new PrincipalKeyCredential("principal", "password"), "mit-kdc", "true", true, false); + } + + @Test public void testEnableKerberos_ManageIdentitiesFalseKdcNone() throws Exception { testEnableKerberos(new PrincipalKeyCredential("principal", "password"), "none", "false", true, false); } @@ -859,6 +864,229 @@ public class KerberosHelperTest extends EasyMockSupport { } + private void testEnableKerberos_UpgradeFromAmbari170KerberizedCluster(final PrincipalKeyCredential PrincipalKeyCredential, + String kdcType, + String manageIdentities, boolean getClusterDescriptor, + boolean getStackDescriptor) throws Exception { + + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + boolean identitiesManaged = (manageIdentities == null) || !"false".equalsIgnoreCase(manageIdentities); + + final StackId stackVersion = createMock(StackId.class); + + final ServiceComponentHost schKerberosClient = createMock(ServiceComponentHost.class); + expect(schKerberosClient.getServiceName()).andReturn(Service.Type.KERBEROS.name()).anyTimes(); + expect(schKerberosClient.getServiceComponentName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes(); + expect(schKerberosClient.getSecurityState()).andReturn(SecurityState.UNSECURED).anyTimes(); + expect(schKerberosClient.getDesiredSecurityState()).andReturn(SecurityState.UNSECURED).anyTimes(); + expect(schKerberosClient.getStackVersion()).andReturn(stackVersion).anyTimes(); + expect(schKerberosClient.getHostName()).andReturn("host1").anyTimes(); + expect(schKerberosClient.getState()).andReturn(State.INSTALLED).anyTimes(); + + final ServiceComponentHost sch1 = createMock(ServiceComponentHost.class); + expect(sch1.getServiceName()).andReturn("SERVICE1").anyTimes(); + expect(sch1.getServiceComponentName()).andReturn("COMPONENT1").anyTimes(); + expect(sch1.getSecurityState()).andReturn(SecurityState.SECURED_KERBEROS).anyTimes(); + expect(sch1.getDesiredSecurityState()).andReturn(SecurityState.SECURED_KERBEROS).anyTimes(); + expect(sch1.getStackVersion()).andReturn(stackVersion).anyTimes(); + expect(sch1.getHostName()).andReturn("host1").anyTimes(); + expect(sch1.getState()).andReturn(State.INSTALLED).anyTimes(); + + sch1.setDesiredSecurityState(SecurityState.SECURED_KERBEROS); + expect(expectLastCall()).once(); + sch1.setSecurityState(SecurityState.SECURING); + expect(expectLastCall()).once(); + + final ServiceComponentHost sch2 = createMock(ServiceComponentHost.class); + expect(sch2.getServiceName()).andReturn("SERVICE2").anyTimes(); + expect(sch2.getServiceComponentName()).andReturn("COMPONENT2").anyTimes(); + expect(sch2.getSecurityState()).andReturn(SecurityState.SECURED_KERBEROS).anyTimes(); + expect(sch2.getDesiredSecurityState()).andReturn(SecurityState.SECURED_KERBEROS).anyTimes(); + expect(sch2.getStackVersion()).andReturn(stackVersion).anyTimes(); + expect(sch2.getHostName()).andReturn("host1").anyTimes(); + expect(sch2.getState()).andReturn(State.INSTALLED).anyTimes(); + + sch2.setDesiredSecurityState(SecurityState.SECURED_KERBEROS); + expect(expectLastCall()).once(); + sch2.setSecurityState(SecurityState.SECURING); + expect(expectLastCall()).once(); + + final Host host = createNiceMock(Host.class); + expect(host.getHostName()).andReturn("host1").anyTimes(); + expect(host.getState()).andReturn(HostState.HEALTHY).anyTimes(); + + final ServiceComponent serviceComponentKerberosClient = createNiceMock(ServiceComponent.class); + expect(serviceComponentKerberosClient.getName()).andReturn(Role.KERBEROS_CLIENT.name()).anyTimes(); + expect(serviceComponentKerberosClient.getServiceComponentHosts()).andReturn(Collections.singletonMap("host1", schKerberosClient)).anyTimes(); + + final Service serviceKerberos = createStrictMock(Service.class); + expect(serviceKerberos.getName()).andReturn(Service.Type.KERBEROS.name()).anyTimes(); + expect(serviceKerberos.getServiceComponents()) + .andReturn(Collections.singletonMap(Role.KERBEROS_CLIENT.name(), serviceComponentKerberosClient)) + .times(1); + serviceKerberos.setSecurityState(SecurityState.SECURED_KERBEROS); + expectLastCall().once(); + + final Service service1 = createStrictMock(Service.class); + expect(service1.getName()).andReturn("SERVICE1").anyTimes(); + expect(service1.getServiceComponents()) + .andReturn(Collections.<String, ServiceComponent>emptyMap()) + .times(1); + 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()) + .times(1); + service2.setSecurityState(SecurityState.SECURED_KERBEROS); + expectLastCall().once(); + + final Map<String, String> kerberosEnvProperties = createMock(Map.class); + expect(kerberosEnvProperties.get("kdc_type")).andReturn(kdcType).anyTimes(); + expect(kerberosEnvProperties.get("manage_identities")).andReturn(manageIdentities).anyTimes(); + expect(kerberosEnvProperties.get("realm")).andReturn("FOOBAR.COM").anyTimes(); + + final Config kerberosEnvConfig = createMock(Config.class); + expect(kerberosEnvConfig.getProperties()).andReturn(kerberosEnvProperties).anyTimes(); + + final Map<String, String> krb5ConfProperties = createMock(Map.class); + + final Config krb5ConfConfig = createMock(Config.class); + expect(krb5ConfConfig.getProperties()).andReturn(krb5ConfProperties).anyTimes(); + + final Cluster cluster = createMock(Cluster.class); + expect(cluster.getHosts()).andReturn(Arrays.asList(host)).anyTimes(); + expect(cluster.getClusterId()).andReturn(1L).anyTimes(); + expect(cluster.getSecurityType()).andReturn(SecurityType.KERBEROS).anyTimes(); + expect(cluster.getDesiredConfigByType("krb5-conf")).andReturn(krb5ConfConfig).anyTimes(); + expect(cluster.getDesiredConfigByType("kerberos-env")).andReturn(kerberosEnvConfig).anyTimes(); + expect(cluster.getClusterName()).andReturn("c1").anyTimes(); + expect(cluster.getServices()) + .andReturn(new HashMap<String, Service>() { + { + put(Service.Type.KERBEROS.name(), serviceKerberos); + put("SERVICE1", service1); + put("SERVICE2", service2); + } + }) + .anyTimes(); + expect(cluster.getServiceComponentHosts("host1")) + .andReturn(new ArrayList<ServiceComponentHost>() { + { + add(schKerberosClient); + add(sch1); + add(sch2); + } + }) + .once(); + expect(cluster.getCurrentStackVersion()) + .andReturn(new StackId("HDP", "2.2")) + .anyTimes(); + expect(cluster.getServiceComponentHosts("KERBEROS", "KERBEROS_CLIENT")).andReturn( + Arrays.asList(schKerberosClient) + ).once(); + + if (identitiesManaged) { + final Clusters clusters = injector.getInstance(Clusters.class); + expect(clusters.getHost("host1")) + .andReturn(host) + .once(); + } + + final AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class); + expect(ambariManagementController.findConfigurationTagsWithOverrides(cluster, null)) + .andReturn(Collections.<String, Map<String, String>>emptyMap()) + .once(); + expect(ambariManagementController.getRoleCommandOrder(cluster)) + .andReturn(createMock(RoleCommandOrder.class)) + .once(); + + final KerberosServiceDescriptor serviceDescriptor1 = createMock(KerberosServiceDescriptor.class); + + final KerberosServiceDescriptor serviceDescriptor2 = createMock(KerberosServiceDescriptor.class); + + final KerberosDescriptor kerberosDescriptor = createMock(KerberosDescriptor.class); + expect(kerberosDescriptor.getService("KERBEROS")).andReturn(null).once(); + expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once(); + expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once(); + + if (getClusterDescriptor) { + setupGetDescriptorFromCluster(kerberosDescriptor); + } else if (getStackDescriptor) { + setupGetDescriptorFromStack(kerberosDescriptor); + } + + 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 Preparation Stage + expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.addStages(anyObject(List.class)); + expectLastCall().once(); + + if (identitiesManaged) { + // Create Principals Stage + expect(requestStageContainer.getLastStageId()).andReturn(-1L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.addStages(anyObject(List.class)); + expectLastCall().once(); + // Create Keytabs Stage + expect(requestStageContainer.getLastStageId()).andReturn(0L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.addStages(anyObject(List.class)); + expectLastCall().once(); + // Distribute Keytabs Stage + expect(requestStageContainer.getLastStageId()).andReturn(1L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.addStages(anyObject(List.class)); + expectLastCall().once(); + } + // Update Configs Stage + expect(requestStageContainer.getLastStageId()).andReturn(2L).anyTimes(); + 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.getLastStageId()).andReturn(3L).anyTimes(); + expect(requestStageContainer.getId()).andReturn(1L).once(); + requestStageContainer.addStages(anyObject(List.class)); + expectLastCall().once(); + + replayAll(); + + // Needed by infrastructure + metaInfo.init(); + + CredentialStoreService credentialStoreService = injector.getInstance(CredentialStoreService.class); + credentialStoreService.setCredential(cluster.getClusterName(), KerberosHelper.KDC_ADMINISTRATOR_CREDENTIAL_ALIAS, + PrincipalKeyCredential, CredentialStoreType.TEMPORARY); + + kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, requestStageContainer, null); + + verifyAll(); + } + private void testEnableKerberos(final PrincipalKeyCredential PrincipalKeyCredential, String kdcType, String manageIdentities, boolean getClusterDescriptor,
