Repository: ambari Updated Branches: refs/heads/trunk c242beeac -> 5e930e44c
AMBARI-9364. Handle hosts/services/components being added to a kerberized cluster. Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/1dd3ad21 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/1dd3ad21 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/1dd3ad21 Branch: refs/heads/trunk Commit: 1dd3ad2178dc1b1a11511ce163a64aa78d3dfdd7 Parents: c242bee Author: John Speidel <jspei...@hortonworks.com> Authored: Tue Jan 27 18:44:59 2015 -0500 Committer: John Speidel <jspei...@hortonworks.com> Committed: Tue Jan 27 19:37:16 2015 -0500 ---------------------------------------------------------------------- .../server/controller/KerberosHelper.java | 115 ++++++++++++- .../internal/HostComponentResourceProvider.java | 47 +++++- .../server/controller/KerberosHelperTest.java | 169 +++++++++++++++++-- .../HostComponentResourceProviderTest.java | 129 +++++++++++++- 4 files changed, 436 insertions(+), 24 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/1dd3ad21/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java index c537498..6bb9bf1 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/KerberosHelper.java @@ -29,8 +29,21 @@ 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.ArtifactResourceProvider; +import org.apache.ambari.server.controller.internal.RequestImpl; import org.apache.ambari.server.controller.internal.RequestResourceFilter; import org.apache.ambari.server.controller.internal.RequestStageContainer; +import org.apache.ambari.server.controller.spi.ClusterController; +import org.apache.ambari.server.controller.spi.NoSuchParentResourceException; +import org.apache.ambari.server.controller.spi.NoSuchResourceException; +import org.apache.ambari.server.controller.spi.Predicate; +import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.spi.ResourceProvider; +import org.apache.ambari.server.controller.spi.SystemException; +import org.apache.ambari.server.controller.spi.UnsupportedPropertyException; +import org.apache.ambari.server.controller.utilities.ClusterControllerHelper; +import org.apache.ambari.server.controller.utilities.PredicateBuilder; import org.apache.ambari.server.metadata.RoleCommandOrder; import org.apache.ambari.server.serveraction.ServerAction; import org.apache.ambari.server.serveraction.kerberos.*; @@ -64,6 +77,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -76,6 +90,16 @@ public class KerberosHelper { private static final Logger LOG = LoggerFactory.getLogger(KerberosHelper.class); + /** + * config type which contains the property used to determine if keberos is enabled + */ + private static final String SECURITY_ENABLED_CONFIG_TYPE = "cluster-env"; + + /** + * name of property which states whether kerberos is enabled + */ + private static final String SECURITY_ENABLED_PROPERTY_NAME = "security_enabled"; + @Inject private AmbariCustomCommandExecutionHelper customCommandExecutionHelper; @@ -107,6 +131,12 @@ public class KerberosHelper { private KerberosOperationHandlerFactory kerberosOperationHandlerFactory; /** + * Used to get kerberos descriptors associated with the cluster or stack. + * Currently not available via injection. + */ + private static ClusterController clusterController = null; + + /** * The Handler implementation that provides the logic to enable Kerberos */ private Handler enableKerberosHandler = new EnableKerberosHandler(); @@ -159,6 +189,11 @@ public class KerberosHelper { // Update KerberosDetails with the new security type - the current one in the cluster is the "old" value kerberosDetails.setSecurityType(securityType); + //todo: modify call from cluster state transition to not include descriptor + if (kerberosDescriptor == null) { + kerberosDescriptor = getClusterDescriptor(cluster); + } + if (securityType == SecurityType.KERBEROS) { LOG.info("Configuring Kerberos for realm {} on cluster, {}", kerberosDetails.getDefaultRealm(), cluster.getClusterName()); requestStageContainer = handle(cluster, kerberosDescriptor, kerberosDetails, null, null, requestStageContainer, enableKerberosHandler); @@ -497,12 +532,12 @@ public class KerberosHelper { } // Ensure the cluster-env/security_enabled flag is set properly - Map<String, String> clusterEnvProperties = kerberosConfigurations.get("cluster-env"); + Map<String, String> clusterEnvProperties = kerberosConfigurations.get(SECURITY_ENABLED_CONFIG_TYPE); if (clusterEnvProperties == null) { clusterEnvProperties = new HashMap<String, String>(); - kerberosConfigurations.put("cluster-env", clusterEnvProperties); + kerberosConfigurations.put(SECURITY_ENABLED_CONFIG_TYPE, clusterEnvProperties); } - clusterEnvProperties.put("security_enabled", + clusterEnvProperties.put(SECURITY_ENABLED_PROPERTY_NAME, (kerberosDetails.getSecurityType() == SecurityType.KERBEROS) ? "true" : "false"); // Always set up the necessary stages to perform the tasks needed to complete the operation. @@ -655,6 +690,69 @@ public class KerberosHelper { } /** + * Get the cluster kerberos descriptor that was registered to the + * cluster/:clusterName/artifacts/kerberos_descriptor endpoint if + * it exists. If not, obtain the default cluster descriptor which + * is available from the endpoint + * stacks/:stackName/versions/:version/artifacts/kerberos_descriptor. + * + * @param cluster cluster instance + * + * @return the kerberos descriptor associated with the specified cluster + * @throws AmbariException if unable to obtain the descriptor + */ + private KerberosDescriptor getClusterDescriptor(Cluster cluster) throws AmbariException { + KerberosDescriptor descriptor; + PredicateBuilder pb = new PredicateBuilder(); + Predicate predicate = pb.begin().property("Artifacts/cluster_name").equals(cluster.getClusterName()).and(). + property(ArtifactResourceProvider.ARTIFACT_NAME_PROPERTY).equals("kerberos_descriptor"). + end().toPredicate(); + + synchronized (KerberosHelper.class) { + if (clusterController == null) { + clusterController = ClusterControllerHelper.getClusterController(); + } + } + + ResourceProvider artifactProvider = + clusterController.ensureResourceProvider(Resource.Type.Artifact); + + Request request = new RequestImpl(Collections.<String>emptySet(), + Collections.<Map<String, Object>>emptySet(), Collections.<String, String>emptyMap(), null); + + Set<Resource> response = null; + try { + response = artifactProvider.getResources(request, predicate); + } catch (SystemException e) { + e.printStackTrace(); + throw new AmbariException("An unknown error occurred while trying to obtain the cluster kerberos descriptor", e); + } catch (UnsupportedPropertyException e) { + e.printStackTrace(); + throw new AmbariException("An unknown error occurred while trying to obtain the cluster kerberos descriptor", e); + } catch (NoSuchParentResourceException e) { + // parent cluster doesn't exist. shouldn't happen since we have the cluster instance + e.printStackTrace(); + throw new AmbariException("An unknown error occurred while trying to obtain the cluster kerberos descriptor", e); + } catch (NoSuchResourceException e) { + // no descriptor registered, use the default from the stack + } + + if (response != null && ! response.isEmpty()) { + Resource descriptorResource = response.iterator().next(); + String descriptor_data = (String) descriptorResource.getPropertyValue( + ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY); + + descriptor = KerberosDescriptor.fromJSON(descriptor_data); + } else { + // get default descriptor from stack + StackId stackId = cluster.getCurrentStackVersion(); + descriptor = ambariMetaInfo.getKerberosDescriptor(stackId.getStackName(), stackId.getStackVersion()); + } + return descriptor; + } + + + /** * Creates a temporary directory within the system temporary directory * <p/> * The resulting directory is to be removed by the caller when desired. @@ -1064,6 +1162,15 @@ public class KerberosHelper { return new ArrayList<String>(hostNames); } + /** + * Determine if a cluster has kerberos enabled. + * + * @param cluster cluster to test + * @return true if the provided cluster has kerberos enabled; false otherwise + */ + public boolean isClusterKerberosEnabled(Cluster cluster) { + return cluster.getSecurityType() == SecurityType.KERBEROS; + } /** * Handler is an interface that needs to be implemented by toggle handler classes to do the @@ -1429,7 +1536,7 @@ public class KerberosHelper { // 2) remove keytab files // 3) update configurations // 3) restart services - return -1; + return requestStageContainer == null ? -1 : requestStageContainer.getLastStageId(); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/1dd3ad21/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java index 7c7e280..b1e05cc 100644 --- a/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java +++ b/ambari-server/src/main/java/org/apache/ambari/server/controller/internal/HostComponentResourceProvider.java @@ -34,6 +34,7 @@ import com.google.inject.Injector; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.configuration.ComponentSSLConfiguration; import org.apache.ambari.server.controller.AmbariManagementController; +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.ServiceComponentHostRequest; @@ -59,6 +60,7 @@ import com.google.inject.assistedinject.AssistedInject; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.MaintenanceState; +import org.apache.ambari.server.state.SecurityType; import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; import org.apache.ambari.server.state.ServiceComponentHostEvent; @@ -122,6 +124,12 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro @Inject private MaintenanceStateHelper maintenanceStateHelper; + /** + * kerberos helper + */ + @Inject + private KerberosHelper kerberosHelper; + // ----- Constructors ---------------------------------------------------- @@ -406,6 +414,9 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro if (clusterName != null && !clusterName.isEmpty()) { clusterNames.add(clusterName); } + + boolean addKerberosStages = false; + for (ServiceComponentHostRequest request : requests) { validateServiceComponentHostRequest(request); @@ -463,6 +474,11 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro if (request.getDesiredState() != null) { // set desired state on host component newState = State.valueOf(request.getDesiredState()); + + // determine if this state transition will require that kerberos stages are added to request. + // once set to true will stay true + addKerberosStages = addKerberosStages || requiresKerberosStageAddition(oldState, newState, cluster); + // throw exception if desired state isn't a valid desired state (static check) if (!newState.isValidDesiredState()) { throw new IllegalArgumentException("Invalid arguments, invalid" @@ -547,8 +563,16 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro // just getting the first cluster Cluster cluster = clusters.getCluster(clusterNames.iterator().next()); - return getManagementController().addStages(stages, cluster, requestProperties, null, null, null, + RequestStageContainer requestStages = getManagementController().addStages( + stages, cluster, requestProperties, null, null, null, changedScHosts, ignoredScHosts, runSmokeTest, false); + + if (addKerberosStages) { + // adds the necessary kerberos related stages to the request + kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, null, requestStages); + } + + return requestStages; } @Override @@ -607,6 +631,11 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro Set<Resource> matchingResources = getResources(queryRequest, predicate); for (Resource queryResource : matchingResources) { + //todo: this was removed for BUG-28737 and the removal of this breaks + //todo: the new "add hosts" api. BUG-4818 is the root cause and needs + //todo: to be addressed and then this predicate evaluation should be + //todo: uncommented to fix "add hosts". +// if (predicate.evaluate(queryResource)) { Map<String, Object> updateRequestProperties = new HashMap<String, Object>(); // add props from query resource @@ -618,6 +647,7 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro updateRequestProperties.putAll(request.getProperties().iterator().next()); } requests.add(getRequest(updateRequestProperties)); +// } } RequestStageContainer requestStages = modifyResources(new Command<RequestStageContainer>() { @@ -799,6 +829,21 @@ public class HostComponentResourceProvider extends AbstractControllerResourcePro } } + /** + * Determine if kerberos stages need to be added to the request as a result of a + * host component state change. + * + * @param current current host component state + * @param target target host component state + * @param cluster associated cluster + * @return whether kerberos stages should be added to the request + */ + public boolean requiresKerberosStageAddition(State current, State target, Cluster cluster) { + return current == State.INIT && + target == State.INSTALLED && + kerberosHelper.isClusterKerberosEnabled(cluster); + } + // ----- inner classes --------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/1dd3ad21/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 758e741..e976d81 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 @@ -29,7 +29,13 @@ 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.ArtifactResourceProvider; import org.apache.ambari.server.controller.internal.RequestStageContainer; +import org.apache.ambari.server.controller.spi.ClusterController; +import org.apache.ambari.server.controller.spi.Predicate; +import org.apache.ambari.server.controller.spi.Request; +import org.apache.ambari.server.controller.spi.Resource; +import org.apache.ambari.server.controller.spi.ResourceProvider; import org.apache.ambari.server.metadata.RoleCommandOrder; import org.apache.ambari.server.orm.DBAccessor; import org.apache.ambari.server.security.SecurityHelper; @@ -62,14 +68,19 @@ import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor; import org.apache.ambari.server.state.kerberos.KerberosPrincipalType; import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor; import org.apache.ambari.server.state.stack.OsFamily; -import org.easymock.EasyMockSupport; +import org.easymock.Capture; import org.easymock.IAnswer; import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PowerMockIgnore; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import javax.persistence.EntityManager; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -77,15 +88,40 @@ 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 { +import java.util.Set; + +import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.anyObject; +import static org.easymock.EasyMock.capture; +import static org.easymock.EasyMock.expect; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.powermock.api.easymock.PowerMock.createMock; +import static org.powermock.api.easymock.PowerMock.createNiceMock; +import static org.powermock.api.easymock.PowerMock.createStrictMock; +import static org.powermock.api.easymock.PowerMock.expectLastCall; +import static org.powermock.api.easymock.PowerMock.mockStatic; +import static org.powermock.api.easymock.PowerMock.replay; +import static org.powermock.api.easymock.PowerMock.replayAll; +import static org.powermock.api.easymock.PowerMock.reset; +import static org.powermock.api.easymock.PowerMock.verify; +import static org.powermock.api.easymock.PowerMock.verifyAll; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(KerberosDescriptor.class) +@PowerMockIgnore({"javax.crypto.*" }) +@SuppressWarnings("unchecked") +public class KerberosHelperTest { private static Injector injector; + private final ClusterController clusterController = createStrictMock(ClusterController.class); + private final AmbariMetaInfo metaInfo = createNiceMock(AmbariMetaInfo.class); @Before public void setUp() throws Exception { + reset(clusterController); + reset(metaInfo); + final KerberosOperationHandlerFactory kerberosOperationHandlerFactory = createNiceMock(KerberosOperationHandlerFactory.class); expect(kerberosOperationHandlerFactory.getKerberosOperationHandler(KDCType.MIT_KDC)) @@ -137,15 +173,19 @@ public class KerberosHelperTest extends EasyMockSupport { 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(AmbariMetaInfo.class).toInstance(metaInfo); 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)); bind(KerberosOperationHandlerFactory.class).toInstance(kerberosOperationHandlerFactory); + bind(ClusterController.class).toInstance(clusterController); } }); + + //todo: currently don't bind ClusterController due to circular references so can't use @Inject + setClusterController(); } @After @@ -211,13 +251,13 @@ public class KerberosHelperTest extends EasyMockSupport { @Test public void testEnableKerberos() throws Exception { - testEnableKerberos(new KerberosCredential("principal", "password", "keytab")); + testEnableKerberos(new KerberosCredential("principal", "password", "keytab"), false, false); } @Test(expected = IllegalArgumentException.class) public void testEnableKerberosMissingCredentials() throws Exception { try { - testEnableKerberos(null); + testEnableKerberos(null, false, false); } catch (IllegalArgumentException e) { Assert.assertTrue(e.getMessage().startsWith("Missing KDC administrator credentials")); throw e; @@ -227,7 +267,7 @@ public class KerberosHelperTest extends EasyMockSupport { @Test(expected = IllegalArgumentException.class) public void testEnableKerberosInvalidCredentials() throws Exception { try { - testEnableKerberos(new KerberosCredential("invalid_principal", "password", "keytab")); + testEnableKerberos(new KerberosCredential("invalid_principal", "password", "keytab"), false, false); } catch (IllegalArgumentException e) { Assert.assertTrue(e.getMessage().startsWith("Invalid KDC administrator credentials")); throw e; @@ -235,6 +275,16 @@ public class KerberosHelperTest extends EasyMockSupport { } @Test + public void testEnableKerberos_GetKerberosDescriptorFromCluster() throws Exception { + testEnableKerberos(new KerberosCredential("principal", "password", "keytab"), true, false); + } + + @Test + public void testEnableKerberos_GetKerberosDescriptorFromStack() throws Exception { + testEnableKerberos(new KerberosCredential("principal", "password", "keytab"), false, true); + } + + @Test public void testEnsureIdentities() throws Exception { testEnsureIdentities(new KerberosCredential("principal", "password", "keytab")); } @@ -259,7 +309,10 @@ public class KerberosHelperTest extends EasyMockSupport { } } - private void testEnableKerberos(final KerberosCredential kerberosCredential) throws Exception { + private void testEnableKerberos(final KerberosCredential kerberosCredential, + boolean getClusterDescriptor, + boolean getStackDescriptor) throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); final ServiceComponentHost sch1 = createNiceMock(ServiceComponentHost.class); @@ -430,6 +483,13 @@ public class KerberosHelperTest extends EasyMockSupport { expect(kerberosDescriptor.getService("SERVICE1")).andReturn(serviceDescriptor1).once(); expect(kerberosDescriptor.getService("SERVICE2")).andReturn(serviceDescriptor2).once(); + //todo: extract method? + if (getClusterDescriptor) { + // needed to mock the static method fromJson() + 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), @@ -480,13 +540,64 @@ public class KerberosHelperTest extends EasyMockSupport { replayAll(); // Needed by infrastructure - injector.getInstance(AmbariMetaInfo.class).init(); + metaInfo.init(); - kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, kerberosDescriptor, requestStageContainer); + kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, !(getClusterDescriptor || getStackDescriptor) ? + kerberosDescriptor : null, requestStageContainer); verifyAll(); } + private void setupGetDescriptorFromCluster(KerberosDescriptor kerberosDescriptor) throws Exception { + mockStatic(KerberosDescriptor.class); + ResourceProvider resourceProvider = createStrictMock(ResourceProvider.class); + expect(clusterController.ensureResourceProvider(Resource.Type.Artifact)).andReturn(resourceProvider).once(); + + Resource resource = createStrictMock(Resource.class); + Set<Resource> result = Collections.singleton(resource); + + Capture<Predicate> predicateCapture = new Capture<Predicate>(); + Capture<Request> requestCapture = new Capture<Request>(); + + //todo: validate captures + +// PredicateBuilder pb = new PredicateBuilder(); +// Predicate predicate = pb.begin().property("Artifacts/cluster_name").equals(cluster.getClusterName()).and(). +// property(ArtifactResourceProvider.ARTIFACT_NAME_PROPERTY).equals("kerberos_descriptor"). +// end().toPredicate(); + + expect(resourceProvider.getResources(capture(requestCapture), + capture(predicateCapture))).andReturn(result).once(); + + String artifactData = "kerberos descriptor json"; + expect(resource.getPropertyValue(ArtifactResourceProvider.ARTIFACT_DATA_PROPERTY)). + andReturn(artifactData).once(); + + expect(KerberosDescriptor.fromJSON(artifactData)).andReturn(kerberosDescriptor).once(); + } + + private void setupGetDescriptorFromStack(KerberosDescriptor kerberosDescriptor) throws Exception { + mockStatic(KerberosDescriptor.class); + ResourceProvider resourceProvider = createStrictMock(ResourceProvider.class); + expect(clusterController.ensureResourceProvider(Resource.Type.Artifact)).andReturn(resourceProvider).once(); + + Capture<Predicate> predicateCapture = new Capture<Predicate>(); + Capture<Request> requestCapture = new Capture<Request>(); + + //todo: validate captures + +// PredicateBuilder pb = new PredicateBuilder(); +// Predicate predicate = pb.begin().property("Artifacts/cluster_name").equals(cluster.getClusterName()).and(). +// property(ArtifactResourceProvider.ARTIFACT_NAME_PROPERTY).equals("kerberos_descriptor"). +// end().toPredicate(); + + expect(resourceProvider.getResources(capture(requestCapture), + capture(predicateCapture))).andReturn(null).once(); + + // cluster.getCurrentStackVersion expectation is already specified in main test method + expect(metaInfo.getKerberosDescriptor("HDP", "2.2")).andReturn(kerberosDescriptor).once(); + } + private void testEnsureIdentities(final KerberosCredential kerberosCredential) throws Exception { KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); @@ -726,4 +837,38 @@ public class KerberosHelperTest extends EasyMockSupport { verifyAll(); } + + @Test + public void testIsClusterKerberosEnabled_false() throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + Cluster cluster = createStrictMock(Cluster.class); + + expect(cluster.getSecurityType()).andReturn(SecurityType.NONE); + + replay(cluster); + assertFalse(kerberosHelper.isClusterKerberosEnabled(cluster)); + verify(cluster); + } + + @Test + public void testIsClusterKerberosEnabled_true() throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + Cluster cluster = createStrictMock(Cluster.class); + + expect(cluster.getSecurityType()).andReturn(SecurityType.KERBEROS); + + replay(cluster); + assertTrue(kerberosHelper.isClusterKerberosEnabled(cluster)); + verify(cluster); + } + + private void setClusterController() throws Exception { + KerberosHelper kerberosHelper = injector.getInstance(KerberosHelper.class); + + Class<?> c = kerberosHelper.getClass(); + + Field f = c.getDeclaredField("clusterController"); + f.setAccessible(true); + f.set(kerberosHelper, clusterController); + } } http://git-wip-us.apache.org/repos/asf/ambari/blob/1dd3ad21/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java ---------------------------------------------------------------------- diff --git a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java index c6a89ed..337cc74 100644 --- a/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java +++ b/ambari-server/src/test/java/org/apache/ambari/server/controller/internal/HostComponentResourceProviderTest.java @@ -21,6 +21,7 @@ package org.apache.ambari.server.controller.internal; import com.google.inject.Injector; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.controller.AmbariManagementController; +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.ResourceProviderFactory; @@ -35,6 +36,7 @@ import org.apache.ambari.server.controller.utilities.PredicateBuilder; import org.apache.ambari.server.controller.utilities.PropertyHelper; import org.apache.ambari.server.state.Cluster; import org.apache.ambari.server.state.Clusters; +import org.apache.ambari.server.state.SecurityType; import org.apache.ambari.server.state.Service; import org.apache.ambari.server.state.ServiceComponent; import org.apache.ambari.server.state.ServiceComponentHost; @@ -59,6 +61,7 @@ import java.util.Set; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createNiceMock; +import static org.easymock.EasyMock.createStrictMock; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; @@ -302,7 +305,7 @@ public class HostComponentResourceProviderTest { HostComponentResourceProvider provider = new TestHostComponentResourceProvider(PropertyHelper.getPropertyIds(type), PropertyHelper.getKeyPropertyIds(type), - managementController, injector, maintenanceStateHelper); + managementController, injector, maintenanceStateHelper, null); expect(resourceProviderFactory.getHostComponentResourceProvider(anyObject(Set.class), anyObject(Map.class), @@ -351,6 +354,8 @@ public class HostComponentResourceProviderTest { ServiceComponentHost componentHost = createNiceMock(ServiceComponentHost.class); RequestStageContainer stageContainer = createNiceMock(RequestStageContainer.class); MaintenanceStateHelper maintenanceStateHelper = createNiceMock(MaintenanceStateHelper.class); + // INIT->INSTALLED state transition causes check for kerverized cluster + KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class); Collection<String> hosts = new HashSet<String>(); hosts.add("Host100"); @@ -379,7 +384,7 @@ public class HostComponentResourceProviderTest { expect(componentHost.getHostName()).andReturn("Host100").anyTimes(); expect(componentHost.getServiceComponentName()).andReturn("Component100").anyTimes(); expect(response.getMessage()).andReturn("response msg").anyTimes(); - //expect(response.getRequestId()).andReturn(1000L); + //Cluster is default type. Maintenance mode is not being tested here so the default is returned. expect(maintenanceStateHelper.isOperationAllowed(Resource.Type.Cluster, componentHost)).andReturn(true).anyTimes(); @@ -413,16 +418,18 @@ public class HostComponentResourceProviderTest { HostComponentResourceProvider provider = new TestHostComponentResourceProvider(PropertyHelper.getPropertyIds(type), PropertyHelper.getKeyPropertyIds(type), - managementController, injector, maintenanceStateHelper); + managementController, injector, maintenanceStateHelper, kerberosHelper); expect(resourceProviderFactory.getHostComponentResourceProvider(anyObject(Set.class), anyObject(Map.class), eq(managementController))). andReturn(provider).anyTimes(); + expect(kerberosHelper.isClusterKerberosEnabled(cluster)).andReturn(false).once(); + // replay replay(managementController, response, resourceProviderFactory, clusters, cluster, service, - component, componentHost, stageContainer, maintenanceStateHelper); + component, componentHost, stageContainer, maintenanceStateHelper, kerberosHelper); Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put(HostComponentResourceProvider.HOST_COMPONENT_STATE_PROPERTY_ID, "STARTED"); @@ -431,7 +438,108 @@ public class HostComponentResourceProviderTest { assertSame(response, requestResponse); // verify - verify(managementController, response, resourceProviderFactory, stageContainer); + verify(managementController, response, resourceProviderFactory, stageContainer, kerberosHelper); + } + + @Test + public void testInstallAndStart_kerberizedCluster() throws Exception { + Resource.Type type = Resource.Type.HostComponent; + + AmbariManagementController managementController = createMock(AmbariManagementController.class); + RequestStatusResponse response = createNiceMock(RequestStatusResponse.class); + ResourceProviderFactory resourceProviderFactory = createNiceMock(ResourceProviderFactory.class); + Injector injector = createNiceMock(Injector.class); + Clusters clusters = createNiceMock(Clusters.class); + Cluster cluster = createNiceMock(Cluster.class); + Service service = createNiceMock(Service.class); + ServiceComponent component = createNiceMock(ServiceComponent.class); + ServiceComponentHost componentHost = createNiceMock(ServiceComponentHost.class); + RequestStageContainer stageContainer = createNiceMock(RequestStageContainer.class); + MaintenanceStateHelper maintenanceStateHelper = createNiceMock(MaintenanceStateHelper.class); + KerberosHelper kerberosHelper = createStrictMock(KerberosHelper.class); + + Collection<String> hosts = new HashSet<String>(); + hosts.add("Host100"); + + Map<String, String> mapRequestProps = new HashMap<String, String>(); + mapRequestProps.put("context", "Install and start components on added hosts"); + + Set<ServiceComponentHostResponse> nameResponse = new HashSet<ServiceComponentHostResponse>(); + nameResponse.add(new ServiceComponentHostResponse( + "Cluster102", "Service100", "Component100", "Host100", "INIT", "", "INIT", "", null)); + Set<ServiceComponentHostResponse> nameResponse2 = new HashSet<ServiceComponentHostResponse>(); + nameResponse2.add(new ServiceComponentHostResponse( + "Cluster102", "Service100", "Component100", "Host100", "INIT", "", "INSTALLED", "", null)); + + + // set expectations + expect(managementController.getClusters()).andReturn(clusters).anyTimes(); + expect(managementController.findServiceName(cluster, "Component100")).andReturn("Service100").anyTimes(); + expect(clusters.getCluster("Cluster102")).andReturn(cluster).anyTimes(); + expect(cluster.getService("Service100")).andReturn(service).anyTimes(); + expect(service.getServiceComponent("Component100")).andReturn(component).anyTimes(); + expect(component.getServiceComponentHost("Host100")).andReturn(componentHost).anyTimes(); + expect(component.getName()).andReturn("Component100").anyTimes(); + // actual state is always INIT until stages actually execute + expect(componentHost.getState()).andReturn(State.INIT).anyTimes(); + expect(componentHost.getHostName()).andReturn("Host100").anyTimes(); + expect(componentHost.getServiceComponentName()).andReturn("Component100").anyTimes(); + expect(response.getMessage()).andReturn("response msg").anyTimes(); + + //Cluster is default type. Maintenance mode is not being tested here so the default is returned. + expect(maintenanceStateHelper.isOperationAllowed(Resource.Type.Cluster, componentHost)).andReturn(true).anyTimes(); + + expect(managementController.getHostComponents( + EasyMock.<Set<ServiceComponentHostRequest>>anyObject())).andReturn(nameResponse); + expect(managementController.getHostComponents( + EasyMock.<Set<ServiceComponentHostRequest>>anyObject())).andReturn(nameResponse2); + + Map<String, Map<State, List<ServiceComponentHost>>> changedHosts = + new HashMap<String, Map<State, List<ServiceComponentHost>>>(); + List<ServiceComponentHost> changedComponentHosts = Collections.singletonList(componentHost); + changedHosts.put("Component100", Collections.singletonMap(State.INSTALLED, changedComponentHosts)); + + Map<String, Map<State, List<ServiceComponentHost>>> changedHosts2 = + new HashMap<String, Map<State, List<ServiceComponentHost>>>(); + List<ServiceComponentHost> changedComponentHosts2 = Collections.singletonList(componentHost); + changedHosts2.put("Component100", Collections.singletonMap(State.STARTED, changedComponentHosts2)); + + expect(managementController.addStages(null, cluster, mapRequestProps, null, null, null, changedHosts, + Collections.<ServiceComponentHost>emptyList(), false, false)).andReturn(stageContainer).once(); + + expect(managementController.addStages(stageContainer, cluster, mapRequestProps, null, null, null, changedHosts2, + Collections.<ServiceComponentHost>emptyList(), false, false)).andReturn(stageContainer).once(); + + stageContainer.persist(); + expect(stageContainer.getProjectedState("Host100", "Component100")).andReturn(State.INSTALLED).once(); + expect(stageContainer.getRequestStatusResponse()).andReturn(response).once(); + + HostComponentResourceProvider provider = + new TestHostComponentResourceProvider(PropertyHelper.getPropertyIds(type), + PropertyHelper.getKeyPropertyIds(type), + managementController, injector, maintenanceStateHelper, kerberosHelper); + + expect(resourceProviderFactory.getHostComponentResourceProvider(anyObject(Set.class), + anyObject(Map.class), + eq(managementController))). + andReturn(provider).anyTimes(); + + expect(kerberosHelper.isClusterKerberosEnabled(cluster)).andReturn(true).once(); + expect(kerberosHelper.toggleKerberos(cluster, SecurityType.KERBEROS, null, stageContainer)). + andReturn(stageContainer).once(); + + // replay + replay(managementController, response, resourceProviderFactory, clusters, cluster, service, + component, componentHost, stageContainer, maintenanceStateHelper, kerberosHelper); + + Map<String, Object> properties = new LinkedHashMap<String, Object>(); + properties.put(HostComponentResourceProvider.HOST_COMPONENT_STATE_PROPERTY_ID, "STARTED"); + + RequestStatusResponse requestResponse = provider.installAndStart("Cluster102", hosts); + + assertSame(response, requestResponse); + // verify + verify(managementController, response, resourceProviderFactory, stageContainer, kerberosHelper); } @Test @@ -533,7 +641,8 @@ public class HostComponentResourceProviderTest { HostComponentResourceProvider provider = new TestHostComponentResourceProvider(PropertyHelper.getPropertyIds(type), PropertyHelper.getKeyPropertyIds(type), - controller, injector, injector.getInstance(MaintenanceStateHelper.class)); + controller, injector, injector.getInstance(MaintenanceStateHelper.class), + injector.getInstance(KerberosHelper.class)); RequestStageContainer requestStages = provider.updateHostComponents(null, requests, requestProperties, runSmokeTest); requestStages.persist(); return requestStages.getRequestStatusResponse(); @@ -550,14 +659,20 @@ public class HostComponentResourceProviderTest { */ public TestHostComponentResourceProvider(Set<String> propertyIds, Map<Resource.Type, String> keyPropertyIds, AmbariManagementController managementController, Injector injector, - MaintenanceStateHelper maintenanceStateHelper) throws Exception { + MaintenanceStateHelper maintenanceStateHelper, + KerberosHelper kerberosHelper) throws Exception { super(propertyIds, keyPropertyIds, managementController, injector); Class<?> c = getClass().getSuperclass(); + Field f = c.getDeclaredField("maintenanceStateHelper"); f.setAccessible(true); f.set(this, maintenanceStateHelper); + + f = c.getDeclaredField("kerberosHelper"); + f.setAccessible(true); + f.set(this, kerberosHelper); } } }