package io.hops;
import io.hops.metadata.yarn.dal.*;
import io.hops.metadata.yarn.dal.util.YARNOperationType;
import io.hops.metadata.yarn.entity.ContainerStatus;
import io.hops.metadata.yarn.entity.NextHeartbeat;
import io.hops.metadata.yarn.entity.PendingEvent;
import io.hops.transaction.handler.LightWeightRequestHandler;
import io.hops.util.DBUtility;
import io.hops.util.RmStreamingProcessor;
import io.hops.util.RMStorageFactory;
import io.hops.util.YarnAPIStorageFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.net.Node;
import org.apache.hadoop.net.NodeBase;
import org.apache.hadoop.util.Time;
import org.apache.hadoop.yarn.api.records.NodeId;
import org.apache.hadoop.yarn.api.records.NodeState;
import org.apache.hadoop.yarn.api.records.Resource;
import org.apache.hadoop.yarn.conf.YarnConfiguration;
import org.apache.hadoop.yarn.event.Dispatcher;
import org.apache.hadoop.yarn.server.resourcemanager.MockNM;
import org.apache.hadoop.yarn.server.resourcemanager.MockRM;
import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNode;
import org.apache.hadoop.yarn.server.resourcemanager.rmnode.RMNodeImplDist;
import org.junit.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Created by antonis on 8/24/16.
*/
public class TestStreamingLibrary {
private static final Log LOG = LogFactory.getLog(TestStreamingLibrary.class);
private static Configuration conf;
private static MockRM rm;
private final int GB = 1024;
private int id = 0;
private int getId() {
return id++;
}
@BeforeClass
public static void setUp() throws Exception {
conf = new YarnConfiguration();
// Set configuration options
conf.set(YarnConfiguration.EVENT_RT_CONFIG_PATH, "target/test-classes/RT_EventAPIConfig.ini");
conf.set(YarnConfiguration.EVENT_SHEDULER_CONFIG_PATH, "target/test-classes/RM_EventAPIConfig.ini");
conf.setBoolean(YarnConfiguration.DISTRIBUTED_RM, true);
RMStorageFactory.setConfiguration(conf);
YarnAPIStorageFactory.setConfiguration(conf);
}
@Before
public void initTests() throws Exception {
DBUtility.InitializeDB();
rm = new MockRM(conf);
rm.start();
//wait for the node to have completely started (can be slow on some machines).
Thread.sleep(10000);
}
@After
public void tearDown() throws Exception {
TimeUnit.SECONDS.sleep(2);
rm.stop();
}
@Test
public void testRMReceiveEvents() throws Exception {
LOG.debug("Register NM1");
MockNM nm1 = rm.registerNode("host0:1234", 4 * GB, 4);
LOG.debug("Register NM2");
MockNM nm2 = rm.registerNode("host1:1234", 6 * GB, 6);
LOG.debug("Heartbeat NM1");
nm1.nodeHeartbeat(true);
LOG.debug("Heartbeat NM2");
nm2.nodeHeartbeat(true);
TimeUnit.SECONDS.sleep(2);
nm1.nodeHeartbeat(true);
nm2.nodeHeartbeat(true);
TimeUnit.SECONDS.sleep(4);
}
@Test
public void testAddNode() throws Exception {
FullRMNode toCommit = generateHopRMNode(getId(), PendingEvent.Type.NODE_ADDED,
PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.NEW);
RMNodeWriter rmNodeWriter = new RMNodeWriter(toCommit);
rmNodeWriter.handle();
LOG.debug("Persisted RMNode in DB");
TimeUnit.SECONDS.sleep(1);
// rmNodeWriter = new RMNodeWriter(generateHopRMNode(getId(), PendingEvent.Type.NODE_ADDED,
// PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.NEW));
// rmNodeWriter.handle();
// LOG.debug("Persisted dummy RMNode");
// TimeUnit.SECONDS.sleep(1);
// Node should be added to RM nodes list
Assert.assertTrue("Node " + toCommit.getYarnRMNode().getNodeID(), rm.getRMContext().getRMNodes().containsKey(
toCommit.getYarnRMNode().getNodeID()));
// Node should be added to scheduler node list
Assert.assertNotNull(rm.getResourceScheduler().getNodeReport(toCommit.getYarnRMNode().getNodeID()));
int clusterMemory = rm.getResourceScheduler().getClusterResource().getMemory();
int clusterVCores = rm.getResourceScheduler().getClusterResource().getVirtualCores();
int numOfNodes = rm.getResourceScheduler().getNumClusterNodes();
Assert.assertEquals(toCommit.getYarnRMNode().getTotalCapability().getMemory(), clusterMemory);
Assert.assertEquals(toCommit.getYarnRMNode().getTotalCapability().getVirtualCores(), clusterVCores);
Assert.assertEquals(1, numOfNodes);
}
@Test
public void testRemoveNode() throws Exception {
// First add a new node
FullRMNode addedNode = generateHopRMNode(getId(), PendingEvent.Type.NODE_ADDED,
PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.NEW);
RMNodeWriter rmNodeWriter = new RMNodeWriter(addedNode);
rmNodeWriter.handle();
TimeUnit.SECONDS.sleep(1);
// Dummy insert
FullRMNode dummyNode = generateHopRMNode(getId(), PendingEvent.Type.NODE_ADDED,
PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.NEW);
rmNodeWriter = new RMNodeWriter(dummyNode);
rmNodeWriter.handle();
TimeUnit.SECONDS.sleep(1);
// Node should be added to RM nodes list
Assert.assertTrue("Node " + addedNode.getYarnRMNode().getNodeID(), rm.getRMContext().getRMNodes().containsKey(
addedNode.getYarnRMNode().getNodeID()));
// Decommission node
FullRMNode decNode = generateHopRMNode(addedNode.getId(), PendingEvent.Type.NODE_REMOVED,
PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.DECOMMISSIONED);
rmNodeWriter = new RMNodeWriter(decNode);
rmNodeWriter.handle();
TimeUnit.SECONDS.sleep(3);
Assert.assertNotNull(rm.getRMContext().getInactiveRMNodes().get(
decNode.getYarnRMNode().getNodeID().getHost()));
Assert.assertFalse(rm.getRMContext().getRMNodes().containsKey(decNode.getYarnRMNode().getNodeID()));
int clusterMemory = rm.getResourceScheduler().getClusterResource().getMemory();
int clusterVCores = rm.getResourceScheduler().getClusterResource().getVirtualCores();
int numOfNodes = rm.getResourceScheduler().getNumClusterNodes();
Assert.assertNull(rm.getResourceScheduler().getNodeReport(decNode.getYarnRMNode().getNodeID()));
Assert.assertEquals(dummyNode.getYarnRMNode().getTotalCapability().getMemory(), clusterMemory);
Assert.assertEquals(dummyNode.getYarnRMNode().getTotalCapability().getVirtualCores(), clusterVCores);
Assert.assertEquals(1, numOfNodes);
}
@Test
@Ignore
public void testUpdateNode() throws Exception {
// First add a new node
FullRMNode addedNode = generateHopRMNode(getId(), PendingEvent.Type.NODE_ADDED,
PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.NEW);
RMNodeWriter rmNodeWriter = new RMNodeWriter(addedNode);
rmNodeWriter.handle();
TimeUnit.SECONDS.sleep(1);
// Dummy insert
FullRMNode dummyNode = generateHopRMNode(getId(), PendingEvent.Type.NODE_ADDED,
PendingEvent.Status.SCHEDULER_FINISHED_PROCESSING, NodeState.NEW);
rmNodeWriter = new RMNodeWriter(dummyNode);
rmNodeWriter.handle();
TimeUnit.SECONDS.sleep(1);
// Node should be added to RM nodes list
Assert.assertTrue("Node " + addedNode.getYarnRMNode().getNodeID(), rm.getRMContext().getRMNodes().containsKey(
addedNode.getYarnRMNode().getNodeID()));
// Update Node with newly launched containers
}
private FullRMNode generateHopRMNode(int id, PendingEvent.Type type, PendingEvent.Status status,
NodeState state) {
int contains =0;
RMNode rmNode = new RMNodeImplDist(
NodeId.newInstance("host" + id, 1234),
rm.getRMContext(),
"host" + id,
1337,
8080,
new NodeBase("name", "/location"),
Resource.newInstance(6 * GB, 6),
"1.0");
if (!NodeState.NEW.equals(state)) {
((RMNodeImplDist) rmNode).setState(state.name());
}
io.hops.metadata.yarn.entity.RMNode hopRMNode = new io.hops.metadata.yarn.entity.RMNode(
rmNode.getNodeID().toString(),
rmNode.getHostName(),
rmNode.getCommandPort(),
rmNode.getHttpPort(),
rmNode.getHealthReport(),
rmNode.getLastHealthReportTime(),
rmNode.getState().name(),
rmNode.getNodeManagerVersion(),
id);
contains ++;
io.hops.metadata.yarn.entity.Resource hopResource = new io.hops.metadata.yarn.entity.Resource(
rmNode.getNodeID().toString(),
rmNode.getTotalCapability().getMemory(),
rmNode.getTotalCapability().getVirtualCores(),
id);
contains ++;
NextHeartbeat nextHB = new NextHeartbeat(rmNode.getNodeID().toString(),
true);
PendingEvent pendingEvent = new PendingEvent(rmNode.getNodeID().toString(),
type,
status,
id,contains);
contains ++;
List<ContainerStatus> containerStatuses = generateContainerStatuses(1, rmNode.getNodeID().toString(),pendingEvent.getId().getEventId());
contains++;
pendingEvent.setContains(contains);
return new FullRMNode(rmNode, hopRMNode, pendingEvent, hopResource, nextHB, id,
containerStatuses);
}
private List<ContainerStatus> generateContainerStatuses(int numOfContainers, String rmNodeId,
int pendingEventId) {
List<ContainerStatus> containerStatuses = new ArrayList<>();
for (int i = 0; i < numOfContainers; ++i) {
ContainerStatus contStat = new ContainerStatus(
rmNodeId + "_" + i,
"RUNNING",
"HEALTHY",
1,
rmNodeId,
pendingEventId,
// This is the UpdatedContainerInfo ID
pendingEventId);
containerStatuses.add(contStat);
}
return containerStatuses;
}
private class FullRMNode {
private final int id;
private final RMNode yarnRMNode;
private final io.hops.metadata.yarn.entity.RMNode rmNode;
private final PendingEvent pendingEvent;
private final io.hops.metadata.yarn.entity.Resource resource;
private final NextHeartbeat nextHeartbeat;
private final List<ContainerStatus> containerStatuses;
public FullRMNode(RMNode yarnRMNode, io.hops.metadata.yarn.entity.RMNode rmNode, PendingEvent pendingEvent,
io.hops.metadata.yarn.entity.Resource resource, NextHeartbeat nextHeartbeat, int id,
List<ContainerStatus> containerStatuses) {
this.yarnRMNode = yarnRMNode;
this.rmNode = rmNode;
this.pendingEvent = pendingEvent;
this.resource = resource;
this.nextHeartbeat = nextHeartbeat;
this.id = id;
this.containerStatuses = containerStatuses;
}
public List<ContainerStatus> getContainerStatuses() {
return containerStatuses;
}
public int getId() {
return id;
}
public RMNode getYarnRMNode() {
return yarnRMNode;
}
public io.hops.metadata.yarn.entity.RMNode getRmNode() {
return rmNode;
}
public PendingEvent getPendingEvent() {
return pendingEvent;
}
public io.hops.metadata.yarn.entity.Resource getResource() {
return resource;
}
public NextHeartbeat getNextHeartbeat() {
return nextHeartbeat;
}
}
private class RMNodeWriter extends LightWeightRequestHandler {
private final FullRMNode toCommit;
public RMNodeWriter(FullRMNode toCommit) {
super(YARNOperationType.TEST);
this.toCommit = toCommit;
}
@Override
public Object performTask() throws IOException {
connector.beginTransaction();
connector.writeLock();
RMNodeDataAccess rmNodeDAO = (RMNodeDataAccess) RMStorageFactory
.getDataAccess(RMNodeDataAccess.class);
rmNodeDAO.add(toCommit.getRmNode());
connector.flush();
PendingEventDataAccess pendingEventDAO = (PendingEventDataAccess) RMStorageFactory
.getDataAccess(PendingEventDataAccess.class);
pendingEventDAO.add(toCommit.getPendingEvent());
ResourceDataAccess resourceDAO = (ResourceDataAccess) RMStorageFactory
.getDataAccess(ResourceDataAccess.class);
resourceDAO.add(toCommit.getResource());
NextHeartbeatDataAccess nextHBDAO = (NextHeartbeatDataAccess) RMStorageFactory
.getDataAccess(NextHeartbeatDataAccess.class);
nextHBDAO.update(toCommit.getNextHeartbeat());
ContainerStatusDataAccess contStatDAO = (ContainerStatusDataAccess) RMStorageFactory
.getDataAccess(ContainerStatusDataAccess.class);
contStatDAO.addAll(toCommit.getContainerStatuses());
connector.commit();
return null;
}
}
}