blob: f2a6e91a6111feca788578aaac742fe14a7d2237 [file] [log] [blame]
/*
* 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 java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.H2DatabaseCleaner;
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.ExecutionCommandWrapper;
import org.apache.ambari.server.actionmanager.HostRoleCommand;
import org.apache.ambari.server.actionmanager.HostRoleStatus;
import org.apache.ambari.server.actionmanager.Request;
import org.apache.ambari.server.actionmanager.Stage;
import org.apache.ambari.server.agent.CommandRepository;
import org.apache.ambari.server.agent.ExecutionCommand;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.internal.ComponentResourceProviderTest;
import org.apache.ambari.server.controller.internal.RequestOperationLevel;
import org.apache.ambari.server.controller.internal.RequestResourceFilter;
import org.apache.ambari.server.controller.internal.ServiceResourceProviderTest;
import org.apache.ambari.server.controller.spi.Resource;
import org.apache.ambari.server.metadata.ActionMetadata;
import org.apache.ambari.server.orm.GuiceJpaInitializer;
import org.apache.ambari.server.orm.InMemoryDefaultTestModule;
import org.apache.ambari.server.orm.OrmTestHelper;
import org.apache.ambari.server.orm.dao.RepositoryVersionDAO;
import org.apache.ambari.server.orm.dao.ServiceComponentDesiredStateDAO;
import org.apache.ambari.server.orm.dao.StackDAO;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
import org.apache.ambari.server.orm.entities.ServiceComponentDesiredStateEntity;
import org.apache.ambari.server.orm.entities.ServiceComponentVersionEntity;
import org.apache.ambari.server.orm.entities.StackEntity;
import org.apache.ambari.server.security.TestAuthenticationFactory;
import org.apache.ambari.server.security.authorization.AuthorizationException;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.DesiredConfig;
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.PropertyInfo;
import org.apache.ambari.server.state.RepositoryInfo;
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.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.UserGroupInfo;
import org.apache.ambari.server.state.ValueAttributesInfo;
import org.apache.ambari.server.state.stack.upgrade.RepositoryVersionHelper;
import org.apache.ambari.server.topology.TopologyManager;
import org.apache.ambari.server.utils.StageUtils;
import org.apache.commons.collections.MapUtils;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.EasyMockRule;
import org.easymock.Mock;
import org.easymock.MockType;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.security.core.context.SecurityContextHolder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import junit.framework.Assert;
public class AmbariCustomCommandExecutionHelperTest {
private static final String REQUEST_CONTEXT_PROPERTY = "context";
@Rule
public EasyMockRule mocks = new EasyMockRule(this);
@Mock(type = MockType.NICE)
private ActionManager actionManager;
@Mock(type = MockType.NICE)
private HostRoleCommand hostRoleCommand;
@Mock(type = MockType.NICE)
private ConfigHelper configHelper;
private Injector injector;
private Clusters clusters;
private AmbariManagementController ambariManagementController;
private Capture<Request> requestCapture = EasyMock.newCapture();
private static final String OVERRIDDEN_SERVICE_CHECK_TIMEOUT_VALUE = "550";
@Before
public void setup() throws Exception {
EasyMock.reset(actionManager, hostRoleCommand, configHelper);
InMemoryDefaultTestModule module = new InMemoryDefaultTestModule(){
@Override
protected void configure() {
getProperties().setProperty(Configuration.AGENT_SERVICE_CHECK_TASK_TIMEOUT.getKey(),
OVERRIDDEN_SERVICE_CHECK_TIMEOUT_VALUE);
super.configure();
bind(ActionManager.class).toInstance(actionManager);
bind(ConfigHelper.class).toInstance(configHelper);
}
};
injector = Guice.createInjector(module);
injector.getInstance(GuiceJpaInitializer.class);
ambariManagementController = injector.getInstance(AmbariManagementController.class);
clusters = injector.getInstance(Clusters.class);
StageUtils.setTopologyManager(injector.getInstance(TopologyManager.class));
StageUtils.setConfiguration(injector.getInstance(Configuration.class));
SecurityContextHolder.getContext().setAuthentication(TestAuthenticationFactory.createAdministrator());
createClusterFixture("c1", new StackId("HDP-2.0.6"), "2.0.6-1234", "c1");
EasyMock.expect(hostRoleCommand.getTaskId()).andReturn(1L);
EasyMock.expect(hostRoleCommand.getStageId()).andReturn(1L);
EasyMock.expect(hostRoleCommand.getRoleCommand()).andReturn(RoleCommand.CUSTOM_COMMAND);
EasyMock.expect(hostRoleCommand.getRole()).andReturn(Role.AMBARI_SERVER_ACTION);
EasyMock.expect(hostRoleCommand.getStatus()).andReturn(HostRoleStatus.PENDING);
EasyMock.expect(actionManager.getNextRequestId()).andReturn(1L).anyTimes();
EasyMock.expect(actionManager.getRequestTasks(1L)).andReturn(Collections.singletonList(hostRoleCommand));
StackInfo stackInfo = new StackInfo();
stackInfo.setName("HDP");
stackInfo.setVersion("2.0.6");
StackId stackId = new StackId(stackInfo);
Map<String, DesiredConfig> desiredConfigMap = new HashMap<>();
Map<PropertyInfo, String> userProperties = new HashMap<>();
Map<PropertyInfo, String> groupProperties = new HashMap<>();
PropertyInfo userProperty = new PropertyInfo();
userProperty.setFilename("zookeeper-env.xml");
userProperty.setName("zookeeper-user");
userProperty.setValue("zookeeperUser");
PropertyInfo groupProperty = new PropertyInfo();
groupProperty.setFilename("zookeeper-env.xml");
groupProperty.setName("zookeeper-group");
groupProperty.setValue("zookeeperGroup");
ValueAttributesInfo valueAttributesInfo = new ValueAttributesInfo();
valueAttributesInfo.setType("user");
Set<UserGroupInfo> userGroupEntries = new HashSet<>();
UserGroupInfo userGroupInfo = new UserGroupInfo();
userGroupInfo.setType("zookeeper-env");
userGroupInfo.setName("zookeeper-group");
userGroupEntries.add(userGroupInfo);
valueAttributesInfo.setUserGroupEntries(userGroupEntries);
userProperty.setPropertyValueAttributes(valueAttributesInfo);
userProperties.put(userProperty, "zookeeperUser");
groupProperties.put(groupProperty, "zookeeperGroup");
Map<String, Set<String>> userGroupsMap = new HashMap<>();
userGroupsMap.put("zookeeperUser", new HashSet<>(Arrays.asList("zookeeperGroup")));
Cluster cluster = clusters.getCluster("c1");
EasyMock.expect(configHelper.getPropertiesWithPropertyType(
stackId, PropertyInfo.PropertyType.USER, cluster, desiredConfigMap)).andReturn(userProperties).anyTimes();
EasyMock.expect(configHelper.getPropertiesWithPropertyType(
stackId, PropertyInfo.PropertyType.GROUP, cluster, desiredConfigMap)).andReturn(groupProperties).anyTimes();
EasyMock.expect(configHelper.createUserGroupsMap(stackId, cluster, desiredConfigMap)).andReturn(userGroupsMap).anyTimes();
actionManager.sendActions(EasyMock.capture(requestCapture), EasyMock.anyObject(ExecuteActionRequest.class));
EasyMock.expectLastCall();
}
@After
public void teardown() throws AmbariException, SQLException {
SecurityContextHolder.getContext().setAuthentication(null);
H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
}
@Test
public void testRefreshQueueCustomCommand() throws Exception {
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put(REQUEST_CONTEXT_PROPERTY, "Refresh YARN Capacity Scheduler");
put("command", "REFRESHQUEUES");
}
};
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", "REFRESHQUEUES",
new HashMap<String, String>() {
{
put("forceRefreshConfigTagsBeforeExecution", "true");
}
}, false);
actionRequest.getResourceFilters().add(new RequestResourceFilter("YARN", "RESOURCEMANAGER", Collections.singletonList("c1-c6401")));
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Request request = requestCapture.getValue();
Assert.assertNotNull(request);
Assert.assertNotNull(request.getStages());
Assert.assertEquals(1, request.getStages().size());
Stage stage = request.getStages().iterator().next();
Assert.assertEquals(1, stage.getHosts().size());
List<ExecutionCommandWrapper> commands = stage.getExecutionCommands("c1-c6401");
Assert.assertEquals(1, commands.size());
ExecutionCommand command = commands.get(0).getExecutionCommand();
Assert.assertNotNull(command.getHostLevelParams());
Assert.assertTrue(command.getHostLevelParams().containsKey(ExecutionCommand.KeyNames.USER_GROUPS));
Assert.assertEquals("{\"zookeeperUser\":[\"zookeeperGroup\"]}", command.getHostLevelParams().get(ExecutionCommand.KeyNames.USER_GROUPS));
Assert.assertEquals(true, command.getForceRefreshConfigTagsBeforeExecution());
}
@Test
public void testHostsFilterHealthy() throws Exception {
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put("context" , "Restart all components for GANGLIA");
put("operation_level/level", "SERVICE");
put("operation_level/service_name", "GANGLIA");
put("operation_level/cluster_name", "c1");
}
};
ExecuteActionRequest actionRequest = new ExecuteActionRequest(
"c1", "RESTART", null,
Arrays.asList(
new RequestResourceFilter("GANGLIA", "GANGLIA_SERVER", Collections.singletonList("c1-c6401")),
new RequestResourceFilter("GANGLIA", "GANGLIA_MONITOR", Collections.singletonList("c1-c6401")),
new RequestResourceFilter("GANGLIA", "GANGLIA_MONITOR", Collections.singletonList("c1-c6402"))
),
new RequestOperationLevel(Resource.Type.Service, "c1", "GANGLIA", null, null),
new HashMap<String, String>(), false);
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Request request = requestCapture.getValue();
Assert.assertNotNull(request);
Assert.assertNotNull(request.getStages());
Assert.assertEquals(1, request.getStages().size());
Stage stage = request.getStages().iterator().next();
// Check if was generated command, one for each host
Assert.assertEquals(2, stage.getHostRoleCommands().size());
}
@Test
public void testHostsFilterUnhealthyHost() throws Exception {
// Set custom status to host
clusters.getHost("c1-c6402").setState(HostState.HEARTBEAT_LOST);
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put("context", "Restart all components for GANGLIA");
put("operation_level/level", "SERVICE");
put("operation_level/service_name", "GANGLIA");
put("operation_level/cluster_name", "c1");
}
};
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", "RESTART", null,
Arrays.asList(
new RequestResourceFilter("GANGLIA", "GANGLIA_SERVER", Collections.singletonList("c1-c6401")),
new RequestResourceFilter("GANGLIA", "GANGLIA_MONITOR", Collections.singletonList("c1-c6401")),
new RequestResourceFilter("GANGLIA", "GANGLIA_MONITOR", Collections.singletonList("c1-c6402"))),
new RequestOperationLevel(Resource.Type.Service, "c1", "GANGLIA", null, null),
new HashMap<String, String>(), false);
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Request request = requestCapture.getValue();
Assert.assertNotNull(request);
Assert.assertNotNull(request.getStages());
Assert.assertEquals(1, request.getStages().size());
Stage stage = request.getStages().iterator().next();
// Check if was generated command for one health host
Assert.assertEquals(1, stage.getHostRoleCommands().size());
}
@Test
public void testHostsFilterUnhealthyComponent() throws Exception {
// Set custom status to host
clusters.getCluster("c1").getService("GANGLIA").getServiceComponent(
"GANGLIA_MONITOR").getServiceComponentHost("c1-c6402").setState(State.UNKNOWN);
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put("context", "Restart all components for GANGLIA");
put("operation_level/level", "SERVICE");
put("operation_level/service_name", "GANGLIA");
put("operation_level/cluster_name", "c1");
}
};
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", "RESTART", null,
Arrays.asList(
new RequestResourceFilter("GANGLIA", "GANGLIA_SERVER", Collections.singletonList("c1-c6401")),
new RequestResourceFilter("GANGLIA", "GANGLIA_MONITOR", Collections.singletonList("c1-c6401")),
new RequestResourceFilter("GANGLIA", "GANGLIA_MONITOR", Collections.singletonList("c1-c6402"))),
new RequestOperationLevel(Resource.Type.Host, "c1", "GANGLIA", null, null),
new HashMap<String, String>(), false);
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Request request = requestCapture.getValue();
Assert.assertNotNull(request);
Assert.assertNotNull(request.getStages());
Assert.assertEquals(1, request.getStages().size());
Stage stage = request.getStages().iterator().next();
// Check if was generated command for one health host
Assert.assertEquals(1, stage.getHostRoleCommands().size());
}
/**
* Tests that trying to run a service check when there are no available hosts
* will throw an exception.
*/
@Test(expected = AmbariException.class)
public void testNoCandidateHostThrowsException() throws Exception {
long clusterId = clusters.getCluster("c1").getClusterId();
// put host into MM
clusters.getHost("c6402").setMaintenanceState(clusterId, MaintenanceState.ON);
// ensure that service check is added for ZOOKEEPER
injector.getInstance(ActionMetadata.class).addServiceCheckAction("ZOOKEEPER");
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put("context", "Service Check ZooKeeper");
put("operation_level/level", "SERVICE");
put("operation_level/service_name", "ZOOKEEPER");
put("operation_level/cluster_name", "c1");
}
};
// create the service check on the host in MM
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1",
"ZOOKEEPER_QUORUM_SERVICE_CHECK",
null, Collections.singletonList(new RequestResourceFilter("ZOOKEEPER", "ZOOKEEPER_CLIENT",
Collections.singletonList("c6402"))),
new RequestOperationLevel(Resource.Type.Service, "c1", "ZOOKEEPER", null, null),
new HashMap<String, String>(), false);
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Assert.fail(
"Expected an exception since there are no hosts which can run the ZK service check");
}
/**
* Tests that client-only services like TEZ are not run on hosts which are in
* MM. The client-only service is a special path since a component is
* typically not specified in the request.
*/
@Test(expected = AmbariException.class)
public void testServiceCheckMaintenanceModeWithMissingComponentName() throws Exception {
long clusterId = clusters.getCluster("c1").getClusterId();
// put host into MM
clusters.getHost("c6402").setMaintenanceState(clusterId, MaintenanceState.ON);
// ensure that service check is added for ZOOKEEPER
injector.getInstance(ActionMetadata.class).addServiceCheckAction("ZOOKEEPER");
// !!! use a null operation level to have us guess at the component
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put("context", "Service Check ZooKeeper");
put("operation_level/level", null);
put("operation_level/service_name", "ZOOKEEPER");
put("operation_level/cluster_name", "c1");
}
};
// create the service check on the host in MM, passing in null for the
// component name
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1",
"ZOOKEEPER_QUORUM_SERVICE_CHECK", null, Collections.singletonList(new RequestResourceFilter("ZOOKEEPER", null,
Collections.singletonList("c6402"))),
new RequestOperationLevel(Resource.Type.Service, "c1", "ZOOKEEPER", null, null),
new HashMap<String, String>(), false);
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Assert.fail("Expected an exception since there are no hosts which can run the ZK service check");
}
@Test(expected = AmbariException.class)
public void testServiceCheckComponentWithEmptyHosts() throws Exception {
AmbariCustomCommandExecutionHelper ambariCustomCommandExecutionHelper = injector.getInstance(AmbariCustomCommandExecutionHelper.class);
List<RequestResourceFilter> requestResourceFilter = new ArrayList<RequestResourceFilter>() {{
add(new RequestResourceFilter("FLUME", null, null));
}};
ActionExecutionContext actionExecutionContext = new ActionExecutionContext("c1", "SERVICE_CHECK", requestResourceFilter);
Stage stage = EasyMock.niceMock(Stage.class);
ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<String, String>(), null);
Assert.fail("Expected an exception since there are no hosts which can run the Flume service check");
}
@Test
public void testServiceCheckWithOverriddenTimeout() throws Exception {
AmbariCustomCommandExecutionHelper ambariCustomCommandExecutionHelper = injector.getInstance(AmbariCustomCommandExecutionHelper.class);
Cluster c1 = clusters.getCluster("c1");
Service s = c1.getService("ZOOKEEPER");
ServiceComponent sc = s.getServiceComponent("ZOOKEEPER_CLIENT");
Assert.assertTrue(sc.getServiceComponentHosts().keySet().size() > 1);
// There are multiple hosts with ZK Client.
List<RequestResourceFilter> requestResourceFilter = new ArrayList<RequestResourceFilter>() {{
add(new RequestResourceFilter("ZOOKEEPER", "ZOOKEEPER_CLIENT", Arrays.asList(new String[]{"c1-c6401"})));
}};
ActionExecutionContext actionExecutionContext = new ActionExecutionContext("c1", "SERVICE_CHECK", requestResourceFilter);
Stage stage = EasyMock.niceMock(Stage.class);
ExecutionCommandWrapper execCmdWrapper = EasyMock.niceMock(ExecutionCommandWrapper.class);
ExecutionCommand execCmd = EasyMock.niceMock(ExecutionCommand.class);
Capture<Map<String,String>> timeOutCapture = EasyMock.newCapture();
EasyMock.expect(stage.getClusterName()).andReturn("c1");
EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6401"), EasyMock.anyString())).andReturn(execCmdWrapper);
EasyMock.expect(execCmdWrapper.getExecutionCommand()).andReturn(execCmd);
execCmd.setCommandParams(EasyMock.capture(timeOutCapture));
EasyMock.expectLastCall();
HashSet<String> localComponents = new HashSet<>();
EasyMock.expect(execCmd.getLocalComponents()).andReturn(localComponents).anyTimes();
EasyMock.replay(configHelper, stage, execCmdWrapper, execCmd);
ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<String, String>(), null);
Map<String, String> configMap = timeOutCapture.getValues().get(0);
for (Map.Entry<String, String> config : configMap.entrySet()) {
if (config.getKey().equals(ExecutionCommand.KeyNames.COMMAND_TIMEOUT)) {
Assert.assertEquals("Service check timeout should be equal to populated in configs",
OVERRIDDEN_SERVICE_CHECK_TIMEOUT_VALUE,
config.getValue());
return;
}
}
Assert.fail("Expected \"command_timeout\" config not found in execution command configs");
}
/**
* Perform a Service Check for ZOOKEEPER/ZOOKEEPER_CLIENT without specifying a host to run in the request.
* This should cause Ambari to randomly pick one of the ZOOKEEPER_CLIENT hosts.
* The current logic first excludes hosts in maintenance mode or that are not healthy (i.e., not heartbeating).
* From that candidate list, if any hosts have 0 IN-PROGRESS tasks, it randomly picks from that set.
* Otherwise, it picks from all candidate hosts.
* @throws Exception
*/
@Test
public void testServiceCheckPicksRandomHost() throws Exception {
AmbariCustomCommandExecutionHelper ambariCustomCommandExecutionHelper = injector.getInstance(AmbariCustomCommandExecutionHelper.class);
Cluster c1 = clusters.getCluster("c1");
Service s = c1.getService("ZOOKEEPER");
ServiceComponent sc = s.getServiceComponent("ZOOKEEPER_CLIENT");
Assert.assertTrue(sc.getServiceComponentHosts().keySet().size() > 1);
// There are multiple hosts with ZK Client.
List<RequestResourceFilter> requestResourceFilter = new ArrayList<RequestResourceFilter>() {{
add(new RequestResourceFilter("ZOOKEEPER", "ZOOKEEPER_CLIENT", null));
}};
ActionExecutionContext actionExecutionContext = new ActionExecutionContext("c1", "SERVICE_CHECK", requestResourceFilter);
Stage stage = EasyMock.niceMock(Stage.class);
ExecutionCommandWrapper execCmdWrapper = EasyMock.niceMock(ExecutionCommandWrapper.class);
ExecutionCommand execCmd = EasyMock.niceMock(ExecutionCommand.class);
EasyMock.expect(stage.getClusterName()).andReturn("c1");
//
EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6401"), EasyMock.anyString())).andReturn(execCmdWrapper);
EasyMock.expect(stage.getExecutionCommandWrapper(EasyMock.eq("c1-c6402"), EasyMock.anyString())).andReturn(execCmdWrapper);
EasyMock.expect(execCmdWrapper.getExecutionCommand()).andReturn(execCmd);
EasyMock.expect(execCmd.getForceRefreshConfigTagsBeforeExecution()).andReturn(true);
HashSet<String> localComponents = new HashSet<>();
EasyMock.expect(execCmd.getLocalComponents()).andReturn(localComponents).anyTimes();
EasyMock.replay(configHelper, stage, execCmdWrapper, execCmd);
ambariCustomCommandExecutionHelper.addExecutionCommandsToStage(actionExecutionContext, stage, new HashMap<String, String>(), null);
}
@Test
public void testIsTopologyRefreshRequired() throws Exception {
AmbariCustomCommandExecutionHelper helper = injector.getInstance(AmbariCustomCommandExecutionHelper.class);
createClusterFixture("c2", new StackId("HDP-2.1.1"), "2.1.1.0-1234", "c2");
Assert.assertTrue(helper.isTopologyRefreshRequired("START", "c2", "HDFS"));
Assert.assertTrue(helper.isTopologyRefreshRequired("RESTART", "c2", "HDFS"));
Assert.assertFalse(helper.isTopologyRefreshRequired("STOP", "c2", "HDFS"));
}
@Test
public void testAvailableServicesMapContainsVersions() throws Exception {
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put(REQUEST_CONTEXT_PROPERTY, "Refresh YARN Capacity Scheduler");
put("command", "REFRESHQUEUES");
}
};
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", "REFRESHQUEUES",
new HashMap<String, String>() {
{
put("forceRefreshConfigTags", "capacity-scheduler");
}
}, false);
actionRequest.getResourceFilters().add(new RequestResourceFilter("YARN", "RESOURCEMANAGER", Collections.singletonList("c1-c6401")));
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
StackId stackId = clusters.getCluster("c1").getDesiredStackVersion();
Request request = requestCapture.getValue();
Stage stage = request.getStages().iterator().next();
List<ExecutionCommandWrapper> commands = stage.getExecutionCommands("c1-c6401");
ExecutionCommand command = commands.get(0).getExecutionCommand();
// ZK is the only service that is versionable
Assert.assertFalse(MapUtils.isEmpty(command.getComponentVersionMap()));
Assert.assertEquals(1, command.getComponentVersionMap().size());
Assert.assertTrue(command.getComponentVersionMap().containsKey("ZOOKEEPER"));
}
/**
* Tests that if a component's repository is not resolved, then the repo
* version map does not get populated.
*
* @throws Exception
*/
@Test
public void testAvailableServicesMapIsEmptyWhenRepositoriesNotResolved() throws Exception {
// set all repos to resolve=false to verify that we don't get a
// component version map
RepositoryVersionDAO repositoryVersionDAO = injector.getInstance(RepositoryVersionDAO.class);
List<RepositoryVersionEntity> repoVersions = repositoryVersionDAO.findAll();
for (RepositoryVersionEntity repoVersion : repoVersions) {
repoVersion.setResolved(false);
repositoryVersionDAO.merge(repoVersion);
}
Map<String, String> requestProperties = new HashMap<String, String>() {
{
put(REQUEST_CONTEXT_PROPERTY, "Refresh YARN Capacity Scheduler");
put("command", "REFRESHQUEUES");
}
};
ExecuteActionRequest actionRequest = new ExecuteActionRequest("c1", "REFRESHQUEUES",
new HashMap<String, String>() {
{
put("forceRefreshConfigTags", "capacity-scheduler");
}
}, false);
actionRequest.getResourceFilters().add(new RequestResourceFilter("YARN", "RESOURCEMANAGER",
Collections.singletonList("c1-c6401")));
EasyMock.replay(hostRoleCommand, actionManager, configHelper);
ambariManagementController.createAction(actionRequest, requestProperties);
Request request = requestCapture.getValue();
Stage stage = request.getStages().iterator().next();
List<ExecutionCommandWrapper> commands = stage.getExecutionCommands("c1-c6401");
ExecutionCommand command = commands.get(0).getExecutionCommand();
Assert.assertTrue(MapUtils.isEmpty(command.getComponentVersionMap()));
}
@Test
public void testCommandRepository() throws Exception {
Cluster cluster = clusters.getCluster("c1");
Service serviceYARN = cluster.getService("YARN");
Service serviceZK = cluster.getService("ZOOKEEPER");
ServiceComponent componentRM = serviceYARN.getServiceComponent("RESOURCEMANAGER");
ServiceComponent componentZKC = serviceZK.getServiceComponent("ZOOKEEPER_CLIENT");
Host host = clusters.getHost("c1-c6401");
AmbariCustomCommandExecutionHelper helper = injector.getInstance(AmbariCustomCommandExecutionHelper.class);
RepositoryVersionHelper repoHelper = injector.getInstance(RepositoryVersionHelper.class);
StackDAO stackDAO = injector.getInstance(StackDAO.class);
RepositoryVersionDAO repoVersionDAO = injector.getInstance(RepositoryVersionDAO.class);
ServiceComponentDesiredStateDAO componentDAO = injector.getInstance(ServiceComponentDesiredStateDAO.class);
RepositoryVersionHelper repoVersionHelper = injector.getInstance(RepositoryVersionHelper.class);
CommandRepository commandRepo = repoHelper.getCommandRepository(cluster, componentRM, host);
Assert.assertEquals(2, commandRepo.getRepositories().size());
RepositoryInfo ri = new RepositoryInfo();
ri.setBaseUrl("http://foo");
ri.setRepoName("HDP");
ri.setRepoId("new-id");
ri.setOsType("redhat6");
String operatingSystems = repoVersionHelper.serializeOperatingSystems(Collections.singletonList(ri));
StackEntity stackEntity = stackDAO.find(cluster.getDesiredStackVersion().getStackName(),
cluster.getDesiredStackVersion().getStackVersion());
RepositoryVersionEntity repositoryVersion = new RepositoryVersionEntity(stackEntity,
"2.1.1.1-1234", "2.1.1.1-1234", operatingSystems);
repositoryVersion = repoVersionDAO.merge(repositoryVersion);
// add a repo version associated with a component
ServiceComponentDesiredStateEntity componentEntity = componentDAO.findByName(cluster.getClusterId(),
serviceYARN.getName(), componentRM.getName());
ServiceComponentVersionEntity componentVersionEntity = new ServiceComponentVersionEntity();
componentVersionEntity.setRepositoryVersion(repositoryVersion);
componentVersionEntity.setUserName("admin");
componentEntity.setDesiredRepositoryVersion(repositoryVersion);
componentEntity.addVersion(componentVersionEntity);
componentDAO.merge(componentEntity);
// !!! make sure the override is set
commandRepo = repoHelper.getCommandRepository(cluster, componentRM, host);
Assert.assertEquals(1, commandRepo.getRepositories().size());
CommandRepository.Repository repo = commandRepo.getRepositories().iterator().next();
Assert.assertEquals("http://foo", repo.getBaseUrl());
// verify that ZK has no repositories, since we haven't defined a repo version for ZKC
commandRepo = repoHelper.getCommandRepository(cluster, componentZKC, host);
Assert.assertEquals(2, commandRepo.getRepositories().size());
}
private void createClusterFixture(String clusterName, StackId stackId,
String respositoryVersion, String hostPrefix) throws AmbariException, AuthorizationException {
String hostC6401 = hostPrefix + "-c6401";
String hostC6402 = hostPrefix + "-c6402";
OrmTestHelper ormTestHelper = injector.getInstance(OrmTestHelper.class);
RepositoryVersionEntity repositoryVersion = ormTestHelper.getOrCreateRepositoryVersion(stackId,
respositoryVersion);
createCluster(clusterName, stackId.getStackId());
addHost(hostC6401, clusterName);
addHost(hostC6402, clusterName);
Cluster cluster = clusters.getCluster(clusterName);
Assert.assertNotNull(cluster);
createService(clusterName, "YARN", repositoryVersion);
createService(clusterName, "GANGLIA", repositoryVersion);
createService(clusterName, "ZOOKEEPER", repositoryVersion);
createService(clusterName, "FLUME", repositoryVersion);
createServiceComponent(clusterName, "YARN", "RESOURCEMANAGER", State.INIT);
createServiceComponent(clusterName, "YARN", "NODEMANAGER", State.INIT);
createServiceComponent(clusterName, "GANGLIA", "GANGLIA_SERVER", State.INIT);
createServiceComponent(clusterName, "GANGLIA", "GANGLIA_MONITOR", State.INIT);
createServiceComponent(clusterName, "ZOOKEEPER", "ZOOKEEPER_CLIENT", State.INIT);
// this component should be not installed on any host
createServiceComponent(clusterName, "FLUME", "FLUME_HANDLER", State.INIT);
createServiceComponentHost(clusterName, "YARN", "RESOURCEMANAGER", hostC6401, null);
createServiceComponentHost(clusterName, "YARN", "NODEMANAGER", hostC6401, null);
createServiceComponentHost(clusterName, "GANGLIA", "GANGLIA_SERVER", hostC6401, State.INIT);
createServiceComponentHost(clusterName, "GANGLIA", "GANGLIA_MONITOR", hostC6401, State.INIT);
createServiceComponentHost(clusterName, "ZOOKEEPER", "ZOOKEEPER_CLIENT", hostC6401, State.INIT);
createServiceComponentHost(clusterName, "YARN", "NODEMANAGER", hostC6402, null);
createServiceComponentHost(clusterName, "GANGLIA", "GANGLIA_MONITOR", hostC6402, State.INIT);
createServiceComponentHost(clusterName, "ZOOKEEPER", "ZOOKEEPER_CLIENT", hostC6402, State.INIT);
}
private void addHost(String hostname, String clusterName) throws AmbariException {
clusters.addHost(hostname);
setOsFamily(clusters.getHost(hostname), "redhat", "6.3");
clusters.getHost(hostname).setState(HostState.HEALTHY);
if (null != clusterName) {
clusters.mapHostToCluster(hostname, clusterName);
}
}
private void setOsFamily(Host host, String osFamily, String osVersion) {
Map<String, String> hostAttributes = new HashMap<>();
hostAttributes.put("os_family", osFamily);
hostAttributes.put("os_release_version", osVersion);
host.setHostAttributes(hostAttributes);
}
private void createCluster(String clusterName, String stackVersion) throws AmbariException, AuthorizationException {
ClusterRequest r = new ClusterRequest(null, clusterName, State.INSTALLED.name(),
SecurityType.NONE, stackVersion, null);
ambariManagementController.createCluster(r);
}
private void createService(String clusterName, String serviceName,
RepositoryVersionEntity repositoryVersion) throws AmbariException, AuthorizationException {
ServiceRequest r1 = new ServiceRequest(clusterName, serviceName,
repositoryVersion.getId(), null, "false");
Set<ServiceRequest> requests = new HashSet<>();
requests.add(r1);
ServiceResourceProviderTest.createServices(ambariManagementController,
injector.getInstance(RepositoryVersionDAO.class), requests);
}
private void createServiceComponent(String clusterName,
String serviceName, String componentName, State desiredState)
throws AmbariException, AuthorizationException {
String dStateStr = null;
if (desiredState != null) {
dStateStr = desiredState.toString();
}
ServiceComponentRequest r = new ServiceComponentRequest(clusterName,
serviceName, componentName, dStateStr);
Set<ServiceComponentRequest> requests =
new HashSet<>();
requests.add(r);
ComponentResourceProviderTest.createComponents(ambariManagementController, requests);
}
private void createServiceComponentHost(String clusterName, String serviceName, String componentName, String hostname, State desiredState)
throws AmbariException, AuthorizationException {
String dStateStr = null;
if (desiredState != null) {
dStateStr = desiredState.toString();
}
ServiceComponentHostRequest r = new ServiceComponentHostRequest(clusterName,
serviceName, componentName, hostname, dStateStr);
Set<ServiceComponentHostRequest> requests =
new HashSet<>();
requests.add(r);
ambariManagementController.createHostComponents(requests);
}
}