package io.airlift.airship.coordinator; import com.google.common.base.Predicates; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Iterables; import io.airlift.airship.shared.AgentLifecycleState; import io.airlift.airship.shared.AgentStatus; import io.airlift.airship.shared.CoordinatorLifecycleState; import io.airlift.airship.shared.CoordinatorStatus; import io.airlift.airship.shared.SlotStatus; import io.airlift.units.Duration; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.net.URI; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; import static io.airlift.airship.shared.AssignmentHelper.APPLE_ASSIGNMENT; import static io.airlift.airship.shared.AssignmentHelper.BANANA_ASSIGNMENT; import static io.airlift.airship.shared.AssignmentHelper.RESOLVED_APPLE_ASSIGNMENT; import static io.airlift.airship.shared.AssignmentHelper.SHORT_APPLE_ASSIGNMENT; import static io.airlift.airship.shared.SlotLifecycleState.STOPPED; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; public class TestCoordinator { private Coordinator coordinator; private MockProvisioner provisioner; private TestingMavenRepository repository; private CoordinatorStatus coordinatorStatus; @BeforeMethod public void setUp() throws Exception { coordinatorStatus = new CoordinatorStatus(UUID.randomUUID().toString(), CoordinatorLifecycleState.ONLINE, "this-coordinator-instance-id", URI.create("fake://coordinator/internal"), URI.create("fake://coordinator/external"), "/local/location", "this-coordinator-instance-type"); repository = new TestingMavenRepository(); provisioner = new MockProvisioner(); coordinator = new Coordinator(coordinatorStatus, provisioner.getCoordinatorFactory(), provisioner.getAgentFactory(), repository, provisioner, new InMemoryStateManager(), new MockServiceInventory(), new Duration(1, TimeUnit.DAYS), false); } @AfterMethod public void tearDown() throws Exception { repository.destroy(); } @Test public void testStatus() throws Exception { CoordinatorStatus actual = coordinator.status(); assertEquals(actual.getCoordinatorId(), coordinatorStatus.getCoordinatorId()); assertEquals(actual.getState(), CoordinatorLifecycleState.ONLINE); assertEquals(actual.getInstanceId(), coordinatorStatus.getInstanceId()); assertEquals(actual.getLocation(), coordinatorStatus.getLocation()); assertEquals(actual.getInstanceType(), coordinatorStatus.getInstanceType()); assertEquals(actual.getInternalUri(), coordinatorStatus.getInternalUri()); assertEquals(actual.getExternalUri(), coordinatorStatus.getExternalUri()); } @Test public void testGetCoordinatorsDefault() throws Exception { // update the coordinator and verify assertEquals(coordinator.getCoordinators().size(), 1); CoordinatorStatus actual = coordinator.getCoordinators().get(0); assertEquals(actual.getCoordinatorId(), coordinatorStatus.getCoordinatorId()); assertEquals(actual.getState(), CoordinatorLifecycleState.ONLINE); assertEquals(actual.getInstanceId(), coordinatorStatus.getInstanceId()); assertEquals(actual.getLocation(), coordinatorStatus.getLocation()); assertEquals(actual.getInstanceType(), coordinatorStatus.getInstanceType()); assertEquals(actual.getInternalUri(), coordinatorStatus.getInternalUri()); assertEquals(actual.getExternalUri(), coordinatorStatus.getExternalUri()); } @Test public void testCoordinatorDiscovery() throws Exception { String coordinatorId = UUID.randomUUID().toString(); String instanceId = "instance-id"; URI internalUri = URI.create("fake://coordinator/" + instanceId + "/internal"); URI externalUri = URI.create("fake://coordinator/" + instanceId + "/external"); String location = "/unknown/location"; String instanceType = "instance.type"; // add the coordinator to the provisioner CoordinatorStatus status = new CoordinatorStatus(coordinatorId, CoordinatorLifecycleState.ONLINE, instanceId, internalUri, externalUri, location, instanceType); provisioner.addCoordinators(status); // coordinator won't see it until it update is called assertEquals(coordinator.getCoordinators().size(), 1); // update the coordinator coordinator.updateAllCoordinatorsAndWait(); // locate the new coordinator List<CoordinatorStatus> coordinators = coordinator.getCoordinators(); assertEquals(coordinators.size(), 2); CoordinatorStatus actual; if (coordinators.get(0).getInstanceId().equals(coordinatorStatus.getInstanceId())) { actual = coordinators.get(1); } else { actual = coordinators.get(0); assertEquals(coordinators.get(1).getInstanceId(), coordinatorStatus.getInstanceId()); } // verify assertEquals(actual.getCoordinatorId(), coordinatorId); assertEquals(actual.getState(), CoordinatorLifecycleState.ONLINE); assertEquals(actual.getInstanceId(), instanceId); assertEquals(actual.getLocation(), location); assertEquals(actual.getInstanceType(), instanceType); assertEquals(actual.getInternalUri(), internalUri); assertEquals(actual.getExternalUri(), externalUri); } @Test public void testCoordinatorProvision() throws Exception { // provision the coordinator and verify String instanceType = "instance-type"; List<CoordinatorStatus> coordinators = coordinator.provisionCoordinators("coordinator:config:1", 1, instanceType, null, null, null, null, null); assertNotNull(coordinators); assertEquals(coordinators.size(), 1); String instanceId = coordinators.get(0).getInstanceId(); assertNotNull(instanceId); String location = coordinators.get(0).getLocation(); assertNotNull(location); assertEquals(coordinators.get(0).getInstanceType(), instanceType); assertNull(coordinators.get(0).getCoordinatorId()); assertNull(coordinators.get(0).getInternalUri()); assertNull(coordinators.get(0).getExternalUri()); assertEquals(coordinators.get(0).getState(), CoordinatorLifecycleState.PROVISIONING); // coordinator will initially report the coordinator as PROVISIONING assertEquals(coordinator.getCoordinators().size(), 2); assertEquals(coordinator.getCoordinator(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getCoordinator(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getCoordinator(instanceId).getLocation(), location); assertNull(coordinator.getCoordinator(instanceId).getCoordinatorId()); assertNull(coordinator.getCoordinator(instanceId).getInternalUri()); assertNull(coordinator.getCoordinator(instanceId).getExternalUri()); assertEquals(coordinator.getCoordinator(instanceId).getState(), CoordinatorLifecycleState.PROVISIONING); // update coordinator, and verify the coordinator is still ONLINE (coordinators don't have live status like agents coordinator.updateAllCoordinatorsAndWait(); assertEquals(coordinator.getCoordinators().size(), 2); assertEquals(coordinator.getCoordinator(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getCoordinator(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getCoordinator(instanceId).getLocation(), location); assertNull(coordinator.getCoordinator(instanceId).getCoordinatorId()); assertNull(coordinator.getCoordinator(instanceId).getInternalUri()); assertNull(coordinator.getCoordinator(instanceId).getExternalUri()); assertEquals(coordinator.getCoordinator(instanceId).getState(), CoordinatorLifecycleState.PROVISIONING); // start and update the coordinator CoordinatorStatus expectedCoordinatorStatus = provisioner.startCoordinator(instanceId); coordinator.updateAllCoordinatorsAndWait(); assertEquals(coordinator.getCoordinators().size(), 2); assertEquals(coordinator.getCoordinator(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getCoordinator(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getCoordinator(instanceId).getLocation(), location); assertEquals(coordinator.getCoordinator(instanceId).getCoordinatorId(), expectedCoordinatorStatus.getCoordinatorId()); assertEquals(coordinator.getCoordinator(instanceId).getInternalUri(), expectedCoordinatorStatus.getInternalUri()); assertEquals(coordinator.getCoordinator(instanceId).getExternalUri(), expectedCoordinatorStatus.getExternalUri()); assertEquals(coordinator.getCoordinator(instanceId).getState(), CoordinatorLifecycleState.ONLINE); // update and verify nothing changed coordinator.updateAllCoordinatorsAndWait(); assertEquals(coordinator.getCoordinators().size(), 2); assertEquals(coordinator.getCoordinator(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getCoordinator(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getCoordinator(instanceId).getLocation(), location); assertEquals(coordinator.getCoordinator(instanceId).getCoordinatorId(), expectedCoordinatorStatus.getCoordinatorId()); assertEquals(coordinator.getCoordinator(instanceId).getInternalUri(), expectedCoordinatorStatus.getInternalUri()); assertEquals(coordinator.getCoordinator(instanceId).getExternalUri(), expectedCoordinatorStatus.getExternalUri()); assertEquals(coordinator.getCoordinator(instanceId).getState(), CoordinatorLifecycleState.ONLINE); } @Test public void testNoAgents() throws Exception { assertTrue(coordinator.getAgents().isEmpty()); } @Test public void testAgentDiscovery() throws Exception { String agentId = UUID.randomUUID().toString(); URI internalUri = URI.create("fake://agent/" + agentId + "/internal"); URI externalUri = URI.create("fake://agent/" + agentId + "/external"); String instanceId = "instance-id"; String location = "/unknown/location"; String instanceType = "instance.type"; Map<String, Integer> resources = ImmutableMap.of("cpu", 8, "memory", 1024); AgentStatus status = new AgentStatus(agentId, AgentLifecycleState.ONLINE, instanceId, internalUri, externalUri, location, instanceType, ImmutableList.<SlotStatus>of(), resources); // add the agent to the provisioner provisioner.addAgents(status); // coordinator won't see it until it update is called assertTrue(coordinator.getAgents().isEmpty()); // update the coordinator and verify coordinator.updateAllAgentsAndWait(); assertEquals(coordinator.getAgents(), ImmutableList.of(status)); AgentStatus actual = coordinator.getAgents().get(0); assertEquals(actual.getAgentId(), agentId); assertEquals(actual.getState(), AgentLifecycleState.ONLINE); assertEquals(actual.getInstanceId(), instanceId); assertEquals(actual.getLocation(), location); assertEquals(actual.getInstanceType(), instanceType); assertEquals(actual.getInternalUri(), internalUri); assertEquals(actual.getExternalUri(), externalUri); assertEquals(actual.getResources(), resources); } @Test public void testAgentProvision() throws Exception { // provision the agent and verify String instanceType = "instance-type"; List<AgentStatus> agents = coordinator.provisionAgents("agent:config:1", 1, instanceType, null, null, null, null, null); assertNotNull(agents); assertEquals(agents.size(), 1); String instanceId = agents.get(0).getInstanceId(); assertNotNull(instanceId); String location = agents.get(0).getLocation(); assertNotNull(location); assertEquals(agents.get(0).getInstanceType(), instanceType); assertNull(agents.get(0).getAgentId()); assertNull(agents.get(0).getInternalUri()); assertNull(agents.get(0).getExternalUri()); assertEquals(agents.get(0).getState(), AgentLifecycleState.PROVISIONING); // coordinator will initially report the agent as PROVISIONING assertEquals(coordinator.getAgents().size(), 1); assertEquals(coordinator.getAgent(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getAgent(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getAgent(instanceId).getLocation(), location); assertNull(coordinator.getAgent(instanceId).getAgentId()); assertNull(coordinator.getAgent(instanceId).getInternalUri()); assertNull(coordinator.getAgent(instanceId).getExternalUri()); assertEquals(coordinator.getAgent(instanceId).getState(), AgentLifecycleState.PROVISIONING); // update coordinator, and verify the agent is still PROVISIONING coordinator.updateAllAgentsAndWait(); assertEquals(coordinator.getAgents().size(), 1); assertEquals(coordinator.getAgent(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getAgent(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getAgent(instanceId).getLocation(), location); assertNull(coordinator.getAgent(instanceId).getAgentId()); assertNull(coordinator.getAgent(instanceId).getInternalUri()); assertNull(coordinator.getAgent(instanceId).getExternalUri()); assertEquals(coordinator.getAgent(instanceId).getState(), AgentLifecycleState.PROVISIONING); // start the agent, update and verify AgentStatus expectedAgentStatus = provisioner.startAgent(instanceId); coordinator.updateAllAgentsAndWait(); assertEquals(coordinator.getAgents().size(), 1); assertEquals(coordinator.getAgent(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getAgent(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getAgent(instanceId).getLocation(), location); assertEquals(coordinator.getAgent(instanceId).getAgentId(), expectedAgentStatus.getAgentId()); assertEquals(coordinator.getAgent(instanceId).getInternalUri(), expectedAgentStatus.getInternalUri()); assertEquals(coordinator.getAgent(instanceId).getExternalUri(), expectedAgentStatus.getExternalUri()); assertEquals(coordinator.getAgent(instanceId).getState(), AgentLifecycleState.ONLINE); // update and verify nothing changed coordinator.updateAllAgentsAndWait(); assertEquals(coordinator.getAgents().size(), 1); assertEquals(coordinator.getAgent(instanceId).getInstanceId(), instanceId); assertEquals(coordinator.getAgent(instanceId).getInstanceType(), instanceType); assertEquals(coordinator.getAgent(instanceId).getLocation(), location); assertEquals(coordinator.getAgent(instanceId).getAgentId(), expectedAgentStatus.getAgentId()); assertEquals(coordinator.getAgent(instanceId).getInternalUri(), expectedAgentStatus.getInternalUri()); assertEquals(coordinator.getAgent(instanceId).getExternalUri(), expectedAgentStatus.getExternalUri()); assertEquals(coordinator.getAgent(instanceId).getState(), AgentLifecycleState.ONLINE); } @Test public void testInstallWithinShortBinarySpec() { URI agentUri = URI.create("fake://appleServer1/"); provisioner.addAgent(UUID.randomUUID().toString(), agentUri, ImmutableMap.of("cpu", 1, "memory", 512)); coordinator.updateAllAgentsAndWait(); List<SlotStatus> slots = coordinator.install(Predicates.<AgentStatus>alwaysTrue(), 1, SHORT_APPLE_ASSIGNMENT); assertEquals(slots.size(), 1); for (SlotStatus slot : slots) { assertAppleSlot(slot); } } @Test public void testInstallWithinResourceLimit() { URI agentUri = URI.create("fake://appleServer1/"); provisioner.addAgent("instance-id", agentUri, ImmutableMap.of("cpu", 1, "memory", 512)); coordinator.updateAllAgentsAndWait(); List<SlotStatus> slots = coordinator.install(Predicates.<AgentStatus>alwaysTrue(), 1, APPLE_ASSIGNMENT); assertEquals(slots.size(), 1); for (SlotStatus slot : slots) { assertAppleSlot(slot); } } @Test public void testInstallWithinUnlimitedResources() { URI agentUri = URI.create("fake://appleServer1/"); provisioner.addAgent("instance-id", agentUri); coordinator.updateAllAgentsAndWait(); List<SlotStatus> slots = coordinator.install(Predicates.<AgentStatus>alwaysTrue(), 1, APPLE_ASSIGNMENT); assertEquals(slots.size(), 1); for (SlotStatus slot : slots) { assertAppleSlot(slot); } } @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "No agents have the available resources to run the specified binary and configuration.") public void testInstallNotEnoughResources() { URI agentUri = URI.create("fake://appleServer1/"); provisioner.addAgent("instance-id", agentUri, ImmutableMap.of("cpu", 0, "memory", 0)); coordinator.updateAllAgentsAndWait(); coordinator.install(Predicates.<AgentStatus>alwaysTrue(), 1, APPLE_ASSIGNMENT); } @Test(expectedExceptions = IllegalStateException.class, expectedExceptionsMessageRegExp = "No agents have the available resources to run the specified binary and configuration.") public void testInstallResourcesConsumed() { URI agentUri = URI.create("fake://appleServer1/"); provisioner.addAgent("instance-id", agentUri, ImmutableMap.of("cpu", 1, "memory", 512)); coordinator.updateAllAgentsAndWait(); // install an apple server List<SlotStatus> slots = coordinator.install(Predicates.<AgentStatus>alwaysTrue(), 1, APPLE_ASSIGNMENT); assertEquals(slots.size(), 1); assertAppleSlot(Iterables.get(slots, 0)); // try to install a banana server which will fail coordinator.install(Predicates.<AgentStatus>alwaysTrue(), 1, BANANA_ASSIGNMENT); } private void assertAppleSlot(SlotStatus slot) { assertEquals(slot.getAssignment(), RESOLVED_APPLE_ASSIGNMENT); assertEquals(slot.getState(), STOPPED); assertEquals(slot.getResources(), ImmutableMap.of("cpu", 1, "memory", 512)); } }