blob: bfe96b29527b8eca1d37a1b399613536a63e17f0 [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.state.svccomphost;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
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.ServiceComponentNotFoundException;
import org.apache.ambari.server.ServiceNotFoundException;
import org.apache.ambari.server.controller.ServiceComponentHostResponse;
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.ClusterDAO;
import org.apache.ambari.server.orm.dao.HostComponentDesiredStateDAO;
import org.apache.ambari.server.orm.dao.HostComponentStateDAO;
import org.apache.ambari.server.orm.dao.HostDAO;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.HostComponentDesiredStateEntity;
import org.apache.ambari.server.orm.entities.HostComponentStateEntity;
import org.apache.ambari.server.orm.entities.HostEntity;
import org.apache.ambari.server.orm.entities.HostVersionEntity;
import org.apache.ambari.server.orm.entities.RepositoryVersionEntity;
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.ConfigFactory;
import org.apache.ambari.server.state.Host;
import org.apache.ambari.server.state.HostConfig;
import org.apache.ambari.server.state.MaintenanceState;
import org.apache.ambari.server.state.RepositoryVersionState;
import org.apache.ambari.server.state.Service;
import org.apache.ambari.server.state.ServiceComponent;
import org.apache.ambari.server.state.ServiceComponentFactory;
import org.apache.ambari.server.state.ServiceComponentHost;
import org.apache.ambari.server.state.ServiceComponentHostEvent;
import org.apache.ambari.server.state.ServiceComponentHostEventType;
import org.apache.ambari.server.state.ServiceComponentHostFactory;
import org.apache.ambari.server.state.ServiceFactory;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.UpgradeState;
import org.apache.ambari.server.state.configgroup.ConfigGroup;
import org.apache.ambari.server.state.configgroup.ConfigGroupFactory;
import org.apache.ambari.server.state.fsm.InvalidStateTransitionException;
import org.apache.ambari.server.utils.EventBusSynchronizer;
import org.apache.commons.lang3.StringUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
public class ServiceComponentHostTest {
private static final Logger LOG = LoggerFactory.getLogger(ServiceComponentHostTest.class);
@Inject
private Injector injector;
@Inject
private Clusters clusters;
@Inject
private ServiceFactory serviceFactory;
@Inject
private ServiceComponentFactory serviceComponentFactory;
@Inject
private ServiceComponentHostFactory serviceComponentHostFactory;
@Inject
private ConfigFactory configFactory;
@Inject
private ConfigGroupFactory configGroupFactory;
@Inject
private OrmTestHelper helper;
@Inject
private ClusterDAO clusterDAO;
@Inject
private HostDAO hostDAO;
@Inject
private HostComponentDesiredStateDAO hostComponentDesiredStateDAO;
@Inject
private HostComponentStateDAO hostComponentStateDAO;
private String clusterName = "c1";
private String hostName1 = "h1";
private Map<String, String> hostAttributes = new HashMap<>();
private RepositoryVersionEntity repositoryVersion;
@Before
public void setup() throws Exception {
injector = Guice.createInjector(new InMemoryDefaultTestModule());
injector.getInstance(GuiceJpaInitializer.class);
injector.injectMembers(this);
EventBusSynchronizer.synchronizeAmbariEventPublisher(injector);
StackId stackId = new StackId("HDP-2.0.6");
createCluster(stackId, clusterName);
repositoryVersion = helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
hostAttributes.put("os_family", "redhat");
hostAttributes.put("os_release_version", "5.9");
Set<String> hostNames = new HashSet<>();
hostNames.add(hostName1);
addHostsToCluster(clusterName, hostAttributes, hostNames);
}
@After
public void teardown() throws AmbariException, SQLException {
H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector);
}
private ClusterEntity createCluster(StackId stackId, String clusterName) throws AmbariException {
helper.createStack(stackId);
clusters.addCluster(clusterName, stackId);
ClusterEntity clusterEntity = clusterDAO.findByName(clusterName);
Assert.assertNotNull(clusterEntity);
return clusterEntity;
}
private void addHostsToCluster(String clusterName, Map<String, String> hostAttributes, Set<String> hostNames) throws AmbariException {
ClusterEntity clusterEntity = clusterDAO.findByName(clusterName);
List<HostEntity> hostEntities = new ArrayList<>();
for (String hostName : hostNames) {
clusters.addHost(hostName);
Host host = clusters.getHost(hostName);
host.setHostAttributes(hostAttributes);
}
clusterEntity.setHostEntities(hostEntities);
clusterDAO.merge(clusterEntity);
clusters.mapAndPublishHostsToCluster(hostNames, clusterName);
}
private ServiceComponentHost createNewServiceComponentHost(String clusterName,
String svc,
String svcComponent,
String hostName, boolean isClient) throws AmbariException{
Cluster c = clusters.getCluster(clusterName);
Assert.assertNotNull(c.getConfigGroups());
return createNewServiceComponentHost(c, svc, svcComponent, hostName);
}
private ServiceComponentHost createNewServiceComponentHost(
Cluster c,
String svc,
String svcComponent,
String hostName) throws AmbariException{
Service s = null;
try {
s = c.getService(svc);
} catch (ServiceNotFoundException e) {
LOG.debug("Calling service create, serviceName={}", svc);
s = serviceFactory.createNew(c, svc, repositoryVersion);
c.addService(s);
}
ServiceComponent sc = null;
try {
sc = s.getServiceComponent(svcComponent);
} catch (ServiceComponentNotFoundException e) {
sc = serviceComponentFactory.createNew(s, svcComponent);
s.addServiceComponent(sc);
}
ServiceComponentHost impl = serviceComponentHostFactory.createNew(
sc, hostName);
Assert.assertEquals(State.INIT, impl.getState());
Assert.assertEquals(State.INIT, impl.getDesiredState());
Assert.assertEquals(c.getClusterName(), impl.getClusterName());
Assert.assertEquals(c.getClusterId(), impl.getClusterId());
Assert.assertEquals(s.getName(), impl.getServiceName());
Assert.assertEquals(sc.getName(), impl.getServiceComponentName());
Assert.assertEquals(hostName, impl.getHostName());
Assert.assertNotNull(c.getServiceComponentHosts(hostName));
Assert.assertNotNull(sc.getDesiredRepositoryVersion());
return impl;
}
private ServiceComponentHostEvent createEvent(ServiceComponentHostImpl impl,
long timestamp, ServiceComponentHostEventType eventType)
throws AmbariException {
Cluster c = clusters.getCluster(clusterName);
if (c.getConfig("time", String.valueOf(timestamp)) == null) {
Config config = configFactory.createNew (c, "time", String.valueOf(timestamp),
new HashMap<>(), new HashMap<>());
}
switch (eventType) {
case HOST_SVCCOMP_INSTALL:
return new ServiceComponentHostInstallEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp,
impl.getServiceComponent().getDesiredStackId().toString());
case HOST_SVCCOMP_START:
return new ServiceComponentHostStartEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_STOP:
return new ServiceComponentHostStopEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_UNINSTALL:
return new ServiceComponentHostUninstallEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_OP_FAILED:
return new ServiceComponentHostOpFailedEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_OP_SUCCEEDED:
return new ServiceComponentHostOpSucceededEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_OP_IN_PROGRESS:
return new ServiceComponentHostOpInProgressEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_OP_RESTART:
return new ServiceComponentHostOpRestartedEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_DISABLE:
return new ServiceComponentHostDisableEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
case HOST_SVCCOMP_WIPEOUT:
return new ServiceComponentHostWipeoutEvent(
impl.getServiceComponentName(), impl.getHostName(), timestamp);
default:
return null;
}
}
private void runStateChanges(ServiceComponentHostImpl impl,
ServiceComponentHostEventType startEventType,
State startState,
State inProgressState,
State failedState,
State completedState)
throws Exception {
long timestamp = 0;
boolean checkStack = false;
if (startEventType == ServiceComponentHostEventType.HOST_SVCCOMP_INSTALL) {
checkStack = true;
}
Assert.assertEquals(startState,
impl.getState());
ServiceComponentHostEvent startEvent = createEvent(impl, ++timestamp,
startEventType);
long startTime = timestamp;
impl.handleEvent(startEvent);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
if (checkStack) {
Assert.assertNotNull(impl.getServiceComponent().getDesiredStackId());
}
ServiceComponentHostEvent installEvent2 = createEvent(impl, ++timestamp,
startEventType);
boolean exceptionThrown = false;
LOG.info("Transitioning from " + impl.getState() + " " + installEvent2.getType());
try {
impl.handleEvent(installEvent2);
} catch (Exception e) {
exceptionThrown = true;
}
if (impl.getState() == State.INSTALLING || impl.getState() == State.STARTING
|| impl.getState() == State.UNINSTALLING
|| impl.getState() == State.WIPING_OUT
|| impl.getState() == State.STARTED
) {
startTime = timestamp;
// Exception is not expected on valid event
Assert.assertTrue("Exception not thrown on invalid event", !exceptionThrown);
}
else {
Assert.assertTrue("Exception not thrown on invalid event", exceptionThrown);
}
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostOpInProgressEvent inProgressEvent1 = new
ServiceComponentHostOpInProgressEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
impl.handleEvent(inProgressEvent1);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostOpInProgressEvent inProgressEvent2 = new
ServiceComponentHostOpInProgressEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
impl.handleEvent(inProgressEvent2);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostOpFailedEvent failEvent = new
ServiceComponentHostOpFailedEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
long endTime = timestamp;
impl.handleEvent(failEvent);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(endTime, impl.getLastOpEndTime());
Assert.assertEquals(failedState,
impl.getState());
ServiceComponentHostOpRestartedEvent restartEvent = new
ServiceComponentHostOpRestartedEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
startTime = timestamp;
impl.handleEvent(restartEvent);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostOpInProgressEvent inProgressEvent3 = new
ServiceComponentHostOpInProgressEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
impl.handleEvent(inProgressEvent3);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostOpFailedEvent failEvent2 = new
ServiceComponentHostOpFailedEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
endTime = timestamp;
impl.handleEvent(failEvent2);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(endTime, impl.getLastOpEndTime());
Assert.assertEquals(failedState,
impl.getState());
ServiceComponentHostEvent startEvent2 = createEvent(impl, ++timestamp,
startEventType);
startTime = timestamp;
impl.handleEvent(startEvent2);
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostOpInProgressEvent inProgressEvent4 = new
ServiceComponentHostOpInProgressEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
impl.handleEvent(inProgressEvent4);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(inProgressState,
impl.getState());
ServiceComponentHostEvent succeededEvent;
if (startEventType == ServiceComponentHostEventType.HOST_SVCCOMP_START) {
succeededEvent = new ServiceComponentHostStartedEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
} else if (startEventType == ServiceComponentHostEventType.HOST_SVCCOMP_STOP) {
succeededEvent = new ServiceComponentHostStoppedEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
} else {
succeededEvent = new
ServiceComponentHostOpSucceededEvent(impl.getServiceComponentName(),
impl.getHostName(), ++timestamp);
}
endTime = timestamp;
impl.handleEvent(succeededEvent);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(timestamp, impl.getLastOpLastUpdateTime());
Assert.assertEquals(endTime, impl.getLastOpEndTime());
Assert.assertEquals(completedState,
impl.getState());
}
@Test
public void testClientStateFlow() throws Exception {
ServiceComponentHostImpl impl = (ServiceComponentHostImpl)
createNewServiceComponentHost(clusterName, "HDFS", "HDFS_CLIENT", hostName1, true);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_INSTALL,
State.INIT,
State.INSTALLING,
State.INSTALL_FAILED,
State.INSTALLED);
boolean exceptionThrown = false;
try {
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_START,
State.INSTALLED,
State.STARTING,
State.INSTALLED,
State.STARTED);
}
catch (Exception e) {
exceptionThrown = true;
}
Assert.assertTrue("Exception not thrown on invalid event", exceptionThrown);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_UNINSTALL,
State.INSTALLED,
State.UNINSTALLING,
State.UNINSTALLING,
State.UNINSTALLED);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_WIPEOUT,
State.UNINSTALLED,
State.WIPING_OUT,
State.WIPING_OUT,
State.INIT);
// check can be removed
for (State state : State.values()) {
impl.setState(state);
if (state.isRemovableState()) {
Assert.assertTrue(impl.canBeRemoved());
}
else {
Assert.assertFalse(impl.canBeRemoved());
}
}
}
@Test
public void testDaemonStateFlow() throws Exception {
ServiceComponentHostImpl impl = (ServiceComponentHostImpl)
createNewServiceComponentHost(clusterName, "HDFS", "DATANODE", hostName1, false);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_INSTALL,
State.INIT,
State.INSTALLING,
State.INSTALL_FAILED,
State.INSTALLED);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_START,
State.INSTALLED,
State.STARTING,
State.INSTALLED,
State.STARTED);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_STOP,
State.STARTED,
State.STOPPING,
State.STARTED,
State.INSTALLED);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_UNINSTALL,
State.INSTALLED,
State.UNINSTALLING,
State.UNINSTALLING,
State.UNINSTALLED);
runStateChanges(impl, ServiceComponentHostEventType.HOST_SVCCOMP_WIPEOUT,
State.UNINSTALLED,
State.WIPING_OUT,
State.WIPING_OUT,
State.INIT);
}
@Ignore
@Test
public void testJobHandling() {
// TODO fix once jobs are handled
}
@Ignore
@Test
public void testGetAndSetConfigs() {
// FIXME config handling
/*
public Map<String, Config> getDesiredConfigs();
public void updateDesiredConfigs(Map<String, Config> configs);
public Map<String, Config> getConfigs();
public void updateConfigs(Map<String, Config> configs);
*/
}
@Test
public void testGetAndSetBasicInfo() throws AmbariException {
ServiceComponentHost sch = createNewServiceComponentHost(clusterName, "HDFS", "NAMENODE", hostName1, false);
sch.setDesiredState(State.INSTALLED);
sch.setState(State.INSTALLING);
Assert.assertEquals(State.INSTALLING, sch.getState());
Assert.assertEquals(State.INSTALLED, sch.getDesiredState());
}
@Test
@Ignore
//TODO Should be rewritten after actual configs calculate workflow change.
public void testActualConfigs() throws Exception {
ServiceComponentHost sch = createNewServiceComponentHost(clusterName, "HDFS", "NAMENODE", hostName1, false);
sch.setDesiredState(State.INSTALLED);
sch.setState(State.INSTALLING);
Cluster cluster = clusters.getCluster(clusterName);
final ConfigGroup configGroup = configGroupFactory.createNew(cluster, "HDFS",
"cg1", "t1", "", new HashMap<>(), new HashMap<>());
cluster.addConfigGroup(configGroup);
Map<String, Map<String,String>> actual =
new HashMap<String, Map<String, String>>() {{
put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
put("core-site", new HashMap<String,String>() {{ put("tag", "version1");
put(configGroup.getId().toString(), "version2"); }});
}};
//sch.updateActualConfigs(actual);
Map<String, HostConfig> confirm = sch.getActualConfigs();
Assert.assertEquals(2, confirm.size());
Assert.assertTrue(confirm.containsKey("global"));
Assert.assertTrue(confirm.containsKey("core-site"));
Assert.assertEquals(1, confirm.get("core-site").getConfigGroupOverrides().size());
}
@Test
public void testConvertToResponse() throws AmbariException {
ServiceComponentHost sch = createNewServiceComponentHost(clusterName, "HDFS", "DATANODE", hostName1, false);
sch.setDesiredState(State.INSTALLED);
sch.setState(State.INSTALLING);
ServiceComponentHostResponse r = sch.convertToResponse(null);
Assert.assertEquals("HDFS", r.getServiceName());
Assert.assertEquals("DATANODE", r.getComponentName());
Assert.assertEquals(hostName1, r.getHostname());
Assert.assertEquals(clusterName, r.getClusterName());
Assert.assertEquals(State.INSTALLED.toString(), r.getDesiredState());
Assert.assertEquals(State.INSTALLING.toString(), r.getLiveState());
Assert.assertEquals(repositoryVersion.getStackId().toString(), r.getDesiredStackVersion());
Assert.assertFalse(r.isStaleConfig());
// TODO check configs
StringBuilder sb = new StringBuilder();
sch.debugDump(sb);
Assert.assertFalse(sb.toString().isEmpty());
}
@Test
public void testStopInVariousStates() throws AmbariException, InvalidStateTransitionException {
ServiceComponentHost sch = createNewServiceComponentHost(clusterName, "HDFS", "DATANODE", hostName1, false);
ServiceComponentHostImpl impl = (ServiceComponentHostImpl) sch;
sch.setDesiredState(State.STARTED);
sch.setState(State.INSTALLED);
long timestamp = 0;
ServiceComponentHostEvent stopEvent = createEvent(impl, ++timestamp,
ServiceComponentHostEventType.HOST_SVCCOMP_STOP);
long startTime = timestamp;
impl.handleEvent(stopEvent);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(State.STOPPING,
impl.getState());
sch.setState(State.INSTALL_FAILED);
boolean exceptionThrown = false;
try {
impl.handleEvent(stopEvent);
} catch (Exception e) {
exceptionThrown = true;
}
Assert.assertTrue("Exception not thrown on invalid event", exceptionThrown);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
sch.setState(State.INSTALLED);
ServiceComponentHostEvent stopEvent2 = createEvent(impl, ++timestamp,
ServiceComponentHostEventType.HOST_SVCCOMP_STOP);
startTime = timestamp;
impl.handleEvent(stopEvent2);
Assert.assertEquals(startTime, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(State.STOPPING,
impl.getState());
}
@Test
public void testDisableInVariousStates() throws AmbariException, InvalidStateTransitionException {
ServiceComponentHost sch = createNewServiceComponentHost(clusterName, "HDFS",
"DATANODE", hostName1, false);
ServiceComponentHostImpl impl = (ServiceComponentHostImpl) sch;
// Test valid states in which host component can be disabled
long timestamp = 0;
HashSet<State> validStates = new HashSet<>();
validStates.add(State.INSTALLED);
validStates.add(State.INSTALL_FAILED);
validStates.add(State.UNKNOWN);
validStates.add(State.DISABLED);
for (State state : validStates) {
sch.setState(state);
ServiceComponentHostEvent disableEvent = createEvent(impl, ++timestamp,
ServiceComponentHostEventType.HOST_SVCCOMP_DISABLE);
impl.handleEvent(disableEvent);
// TODO: At present operation timestamps are not getting updated.
Assert.assertEquals(-1, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
Assert.assertEquals(State.DISABLED, impl.getState());
}
// Test invalid states in which host component cannot be disabled
HashSet<State> invalidStates = new HashSet<>();
invalidStates.add(State.INIT);
invalidStates.add(State.INSTALLING);
invalidStates.add(State.STARTING);
invalidStates.add(State.STARTED);
invalidStates.add(State.STOPPING);
invalidStates.add(State.UNINSTALLING);
invalidStates.add(State.UNINSTALLED);
invalidStates.add(State.UPGRADING);
for (State state : invalidStates) {
sch.setState(state);
ServiceComponentHostEvent disableEvent = createEvent(impl, ++timestamp,
ServiceComponentHostEventType.HOST_SVCCOMP_DISABLE);
boolean exceptionThrown = false;
try {
impl.handleEvent(disableEvent);
} catch (Exception e) {
exceptionThrown = true;
}
Assert.assertTrue("Exception not thrown on invalid event",
exceptionThrown);
// TODO: At present operation timestamps are not getting updated.
Assert.assertEquals(-1, impl.getLastOpStartTime());
Assert.assertEquals(-1, impl.getLastOpLastUpdateTime());
Assert.assertEquals(-1, impl.getLastOpEndTime());
}
}
@Test
@Ignore
//TODO Should be rewritten after stale configs calculate workflow change.
public void testStaleConfigs() throws Exception {
String stackVersion = "HDP-2.0.6";
StackId stackId = new StackId(stackVersion);
String clusterName = "c2";
createCluster(stackId, clusterName);
final String hostName = "h3";
Set<String> hostNames = new HashSet<>();
hostNames.add(hostName);
addHostsToCluster(clusterName, hostAttributes, hostNames);
final HostEntity hostEntity = hostDAO.findByName(hostName);
Assert.assertNotNull(hostEntity.getHostId());
Cluster cluster = clusters.getCluster(clusterName);
Assert.assertNotNull(cluster);
RepositoryVersionEntity repositoryVersion = helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
ServiceComponentHost sch1 = createNewServiceComponentHost(cluster, "HDFS", "NAMENODE", hostName);
ServiceComponentHost sch2 = createNewServiceComponentHost(cluster, "HDFS", "DATANODE", hostName);
ServiceComponentHost sch3 = createNewServiceComponentHost(cluster, "MAPREDUCE2", "HISTORYSERVER", hostName);
sch1.getServiceComponent().setDesiredRepositoryVersion(repositoryVersion);
sch1.setDesiredState(State.INSTALLED);
sch1.setState(State.INSTALLING);
sch2.setDesiredState(State.INSTALLED);
sch2.setState(State.INSTALLING);
sch3.setDesiredState(State.INSTALLED);
sch3.setState(State.INSTALLING);
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
makeConfig(cluster, "hdfs-site", "version0",
new HashMap<String,String>() {{
put("a", "b");
}}, new HashMap<>());
Map<String, Map<String, String>> actual = new HashMap<String, Map<String, String>>() {{
put("hdfs-site", new HashMap<String,String>() {{ put("tag", "version0"); }});
}};
/*sch1.updateActualConfigs(actual);
sch2.updateActualConfigs(actual);
sch3.updateActualConfigs(actual);*/
makeConfig(cluster, "foo", "version1",
new HashMap<String,String>() {{ put("a", "c"); }}, new HashMap<>());
// HDP-x/HDFS does not define type 'foo', so changes do not count to stale
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
makeConfig(cluster, "hdfs-site", "version1",
new HashMap<String,String>() {{ put("a1", "b1"); }}, new HashMap<>());
// HDP-x/HDFS/hdfs-site is not on the actual, but it is defined, so it is stale
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
actual.put("hdfs-site", new HashMap<String, String>() {{ put ("tag", "version1"); }});
//sch1.updateActualConfigs(actual);
// HDP-x/HDFS/hdfs-site up to date, only for sch1
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
//sch2.updateActualConfigs(actual);
// HDP-x/HDFS/hdfs-site up to date for both
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
makeConfig(cluster, "hdfs-site", "version2",
new HashMap<String, String>() {{ put("dfs.journalnode.http-address", "http://foo"); }},
new HashMap<>());
// HDP-x/HDFS/hdfs-site updated to changed property
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
actual.get("hdfs-site").put("tag", "version2");
/*sch1.updateActualConfigs(actual);
sch2.updateActualConfigs(actual);*/
//reset restartRequired flag + invalidating isStale cache
// after start/restart command execution completed
sch1.setRestartRequired(false);
sch2.setRestartRequired(false);
// HDP-x/HDFS/hdfs-site updated to changed property
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
// make a host override
final Host host = clusters.getHostsForCluster(clusterName).get(hostName);
Assert.assertNotNull(host);
final Config c = configFactory.createNew(cluster, "hdfs-site", "version3",
new HashMap<String, String>() {{ put("dfs.journalnode.http-address", "http://goo"); }},
new HashMap<>());
host.addDesiredConfig(cluster.getClusterId(), true, "user", c);
ConfigGroup configGroup = configGroupFactory.createNew(cluster, "HDFS", "g1",
"t1", "", new HashMap<String, Config>() {{ put("hdfs-site", c); }},
new HashMap<Long, Host>() {{ put(hostEntity.getHostId(), host); }});
cluster.addConfigGroup(configGroup);
// HDP-x/HDFS/hdfs-site updated host to changed property
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
actual.get("hdfs-site").put(configGroup.getId().toString(), "version3");
//sch2.updateActualConfigs(actual);
// HDP-x/HDFS/hdfs-site updated host to changed property
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
//sch1.updateActualConfigs(actual);
// HDP-x/HDFS/hdfs-site updated host to changed property
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
makeConfig(cluster, "mapred-site", "version1",
new HashMap<String, String>() {{ put("a", "b"); }},
new HashMap<>());
actual.put("mapred-site", new HashMap<String, String>() {{ put ("tag", "version1"); }});
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch3.convertToResponse(null).isStaleConfig());
//sch3.updateActualConfigs(actual);
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
// Change core-site property, only HDFS property
makeConfig(cluster, "core-site", "version1",
new HashMap<String,String>() {{
put("a", "b");
put("fs.trash.interval", "360"); // HDFS only
}}, new HashMap<>());
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch3.convertToResponse(null).isStaleConfig());
actual.put("core-site", new HashMap<String, String>() {{
put("tag", "version1");
}});
//sch1.updateActualConfigs(actual);
final Config c1 = configFactory.createNew(cluster, "core-site", "version2",
new HashMap<String, String>() {{ put("fs.trash.interval", "400"); }},
new HashMap<>());
configGroup = configGroupFactory.createNew(cluster, "HDFS", "g2",
"t2", "", new HashMap<String, Config>() {{ put("core-site", c1); }},
new HashMap<Long, Host>() {{ put(hostEntity.getHostId(), host); }});
cluster.addConfigGroup(configGroup);
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch3.convertToResponse(null).isStaleConfig());
// Test actual configs are updated for deleted config group
Long id = configGroup.getId();
HashMap<String, String> tags = new HashMap<>(2);
tags.put("tag", "version1");
tags.put(id.toString(), "version2");
actual.put("core-site", tags);
//sch3.updateActualConfigs(actual);
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
cluster.deleteConfigGroup(id);
Assert.assertNull(cluster.getConfigGroups().get(id));
//sch3.updateActualConfigs(actual);
Assert.assertTrue(sch3.convertToResponse(null).isStaleConfig());
tags.remove(id.toString());
//sch3.updateActualConfigs(actual);
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
}
@Test
@Ignore
//TODO Should be rewritten after stale configs calculate workflow change.
public void testStaleConfigsAttributes() throws Exception {
String stackVersion = "HDP-2.0.6";
StackId stackId = new StackId(stackVersion);
String clusterName = "c2";
createCluster(stackId, clusterName);
final String hostName = "h3";
Set<String> hostNames = new HashSet<>();
hostNames.add(hostName);
addHostsToCluster(clusterName, hostAttributes, hostNames);
Cluster cluster = clusters.getCluster(clusterName);
RepositoryVersionEntity repositoryVersion = helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
ServiceComponentHost sch1 = createNewServiceComponentHost(cluster, "HDFS", "NAMENODE", hostName);
ServiceComponentHost sch2 = createNewServiceComponentHost(cluster, "HDFS", "DATANODE", hostName);
ServiceComponentHost sch3 = createNewServiceComponentHost(cluster, "MAPREDUCE2", "HISTORYSERVER", hostName);
sch1.getServiceComponent().setDesiredRepositoryVersion(repositoryVersion);
sch1.setDesiredState(State.INSTALLED);
sch1.setState(State.INSTALLING);
sch2.setDesiredState(State.INSTALLED);
sch2.setState(State.INSTALLING);
sch3.setDesiredState(State.INSTALLED);
sch3.setState(State.INSTALLING);
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
makeConfig(cluster, "global", "version1",
new HashMap<String,String>() {{
put("a", "b");
put("dfs_namenode_name_dir", "/foo1"); // HDFS only
put("mapred_log_dir_prefix", "/foo2"); // MR2 only
}}, new HashMap<>());
makeConfig(cluster, "hdfs-site", "version1",
new HashMap<String,String>() {{
put("hdfs1", "hdfs1value1");
}}, new HashMap<>());
Map<String, Map<String, String>> actual = new HashMap<String, Map<String, String>>() {{
put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
put("hdfs-site", new HashMap<String,String>() {{ put("tag", "version1"); }});
}};
/*sch1.updateActualConfigs(actual);
sch2.updateActualConfigs(actual);
sch3.updateActualConfigs(actual);*/
makeConfig(cluster, "mapred-site", "version1",
new HashMap<String,String>() {{ put("a", "c"); }},new HashMap<String, Map<String,String>>(){{
put("final", new HashMap<String, String>(){{
put("a", "true");
}});
}});
// HDP-x/HDFS does not define type 'foo', so changes do not count to stale
Assert.assertFalse(sch1.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch2.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch3.convertToResponse(null).isStaleConfig());
actual = new HashMap<String, Map<String, String>>() {{
put("global", new HashMap<String,String>() {{ put("tag", "version1"); }});
put("mapred-site", new HashMap<String,String>() {{ put("tag", "version1"); }});
}};
sch3.setRestartRequired(false);
//sch3.updateActualConfigs(actual);
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
// Now add config-attributes
Map<String, Map<String, String>> c1PropAttributes = new HashMap<>();
c1PropAttributes.put("final", new HashMap<>());
c1PropAttributes.get("final").put("hdfs1", "true");
makeConfig(cluster, "hdfs-site", "version2",
new HashMap<String,String>() {{
put("hdfs1", "hdfs1value1");
}}, c1PropAttributes);
sch1.setRestartRequired(false);
sch2.setRestartRequired(false);
sch3.setRestartRequired(false);
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
// Now change config-attributes
Map<String, Map<String, String>> c2PropAttributes = new HashMap<>();
c2PropAttributes.put("final", new HashMap<>());
c2PropAttributes.get("final").put("hdfs1", "false");
makeConfig(cluster, "hdfs-site", "version3",
new HashMap<String,String>() {{
put("hdfs1", "hdfs1value1");
}}, c2PropAttributes);
sch1.setRestartRequired(false);
sch2.setRestartRequired(false);
sch3.setRestartRequired(false);
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
// Now change config-attributes
makeConfig(cluster, "hdfs-site", "version4",
new HashMap<String,String>() {{
put("hdfs1", "hdfs1value1");
}}, new HashMap<>());
sch1.setRestartRequired(false);
sch2.setRestartRequired(false);
sch3.setRestartRequired(false);
Assert.assertTrue(sch1.convertToResponse(null).isStaleConfig());
Assert.assertTrue(sch2.convertToResponse(null).isStaleConfig());
Assert.assertFalse(sch3.convertToResponse(null).isStaleConfig());
}
/**
* Helper method to create a configuration
* @param cluster the cluster
* @param type the config type
* @param tag the config tag
* @param values the values for the config
*/
private void makeConfig(Cluster cluster, String type, String tag, Map<String, String> values, Map<String, Map<String, String>> attributes) throws AmbariException {
Config config = configFactory.createNew(cluster, type, tag, values, attributes);
cluster.addDesiredConfig("user", Collections.singleton(config));
}
@Test
public void testMaintenance() throws Exception {
String stackVersion = "HDP-2.0.6";
StackId stackId = new StackId(stackVersion);
String clusterName = "c2";
createCluster(stackId, clusterName);
final String hostName = "h3";
Set<String> hostNames = new HashSet<>();
hostNames.add(hostName);
addHostsToCluster(clusterName, hostAttributes, hostNames);
Cluster cluster = clusters.getCluster(clusterName);
helper.getOrCreateRepositoryVersion(stackId, stackId.getStackVersion());
HostEntity hostEntity = hostDAO.findByName(hostName);
Assert.assertNotNull(hostEntity);
ServiceComponentHost sch1 = createNewServiceComponentHost(cluster, "HDFS", "NAMENODE", hostName);
//ServiceComponentHost sch2 = createNewServiceComponentHost(cluster, "HDFS", "DATANODE", hostName);
//ServiceComponentHost sch3 = createNewServiceComponentHost(cluster, "MAPREDUCE2", "HISTORYSERVER", hostName);
HostComponentDesiredStateEntity entity = hostComponentDesiredStateDAO.findByIndex(
cluster.getClusterId(),
sch1.getServiceName(),
sch1.getServiceComponentName(),
hostEntity.getHostId()
);
Assert.assertEquals(MaintenanceState.OFF, entity.getMaintenanceState());
Assert.assertEquals(MaintenanceState.OFF, sch1.getMaintenanceState());
sch1.setMaintenanceState(MaintenanceState.ON);
Assert.assertEquals(MaintenanceState.ON, sch1.getMaintenanceState());
entity = hostComponentDesiredStateDAO.findByIndex(
cluster.getClusterId(),
sch1.getServiceName(),
sch1.getServiceComponentName(),
hostEntity.getHostId()
);
Assert.assertEquals(MaintenanceState.ON, entity.getMaintenanceState());
}
/**
* Tests that the host version for a repository can transition properly to
* CURRENT even if other components on that host have not reported in correct
* for their own repo versions. This assures that the host version logic is
* scoped to the repo that is transitioning and is not affected by other
* components.
*
* @throws Exception
*/
@Test
public void testHostVersionTransitionIsScopedByRepository() throws Exception {
// put the existing host versions OUT_OF_SYNC
HostEntity hostEntity = hostDAO.findByName(hostName1);
Collection<HostVersionEntity> hostVersions = hostEntity.getHostVersionEntities();
Assert.assertEquals(1, hostVersions.size());
hostVersions.iterator().next().setState(RepositoryVersionState.OUT_OF_SYNC);
hostDAO.merge(hostEntity);
ServiceComponentHost namenode = createNewServiceComponentHost(clusterName, "HDFS", "NAMENODE", hostName1, false);
namenode.setDesiredState(State.STARTED);
namenode.setState(State.STARTED);
ServiceComponentHost datanode = createNewServiceComponentHost(clusterName, "HDFS", "DATANODE", hostName1, false);
datanode.setDesiredState(State.STARTED);
datanode.setState(State.STARTED);
ServiceComponentHost zkServer = createNewServiceComponentHost(clusterName, "ZOOKEEPER", "ZOOKEEPER_SERVER", hostName1, false);
zkServer.setDesiredState(State.STARTED);
zkServer.setState(State.STARTED);
ServiceComponentHost zkClient = createNewServiceComponentHost(clusterName, "ZOOKEEPER", "ZOOKEEPER_CLIENT", hostName1, true);
zkClient.setDesiredState(State.STARTED);
zkClient.setState(State.STARTED);
// put some host components into a bad state
hostEntity = hostDAO.findByName(hostName1);
Collection<HostComponentStateEntity> hostComponentStates = hostEntity.getHostComponentStateEntities();
for( HostComponentStateEntity hostComponentState : hostComponentStates ) {
if( StringUtils.equals("HDFS", hostComponentState.getServiceName() ) ) {
hostComponentState.setVersion(State.UNKNOWN.name());
hostComponentStateDAO.merge(hostComponentState);
}
}
// create the repo just for ZK
StackId stackId = new StackId("HDP-2.2.0");
RepositoryVersionEntity patchRepositoryVersion = helper.getOrCreateRepositoryVersion(stackId, "2.2.0.0-1");
// create the new host version
zkServer.getServiceComponent().setDesiredRepositoryVersion(patchRepositoryVersion);
zkClient.getServiceComponent().setDesiredRepositoryVersion(patchRepositoryVersion);
helper.createHostVersion(hostName1, patchRepositoryVersion, RepositoryVersionState.INSTALLED);
// move ZK components to UPGRADED and reporting the new version
hostEntity = hostDAO.findByName(hostName1);
hostComponentStates = hostEntity.getHostComponentStateEntities();
for( HostComponentStateEntity hostComponentState : hostComponentStates ) {
if( StringUtils.equals("ZOOKEEPER", hostComponentState.getServiceName() ) ) {
hostComponentState.setVersion(patchRepositoryVersion.getVersion());
hostComponentState.setUpgradeState(UpgradeState.COMPLETE);
hostComponentStateDAO.merge(hostComponentState);
}
}
hostEntity = hostDAO.merge(hostEntity);
zkServer.recalculateHostVersionState();
// very transition to CURRENT
hostVersions = hostEntity.getHostVersionEntities();
Assert.assertEquals(2, hostVersions.size());
for (HostVersionEntity hostVersion : hostVersions) {
if (hostVersion.getRepositoryVersion().equals(repositoryVersion)) {
Assert.assertEquals(RepositoryVersionState.OUT_OF_SYNC, hostVersion.getState());
} else if (hostVersion.getRepositoryVersion().equals(patchRepositoryVersion)) {
Assert.assertEquals(RepositoryVersionState.CURRENT, hostVersion.getState());
} else {
Assert.fail("Unexpected repository version");
}
}
}
}