This repository has been archived by the owner on Jun 22, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #544 from riccardomc/cli/minimesos-logs
Add "minimesos logs" command
- Loading branch information
Showing
11 changed files
with
494 additions
and
0 deletions.
There are no files selected for viewing
211 changes: 211 additions & 0 deletions
211
cli/src/integration-test/java/com/containersol/minimesos/main/CommandLogsTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
package com.containersol.minimesos.main; | ||
|
||
import com.containersol.minimesos.cluster.ClusterRepository; | ||
import com.containersol.minimesos.cluster.MesosCluster; | ||
import com.containersol.minimesos.cluster.MesosClusterFactory; | ||
import com.containersol.minimesos.mesos.MesosAgentContainer; | ||
import com.containersol.minimesos.mesos.MesosMasterContainer; | ||
import com.containersol.minimesos.state.*; | ||
import com.containersol.minimesos.util.Downloader; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
|
||
import java.io.ByteArrayOutputStream; | ||
import java.io.PrintStream; | ||
import java.io.UnsupportedEncodingException; | ||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
import java.util.*; | ||
|
||
import static java.util.Collections.singletonList; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.mockito.Matchers.any; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.when; | ||
|
||
public class CommandLogsTest { | ||
|
||
private final String slaveId = "de09c926-7be6-47c6-ab9a-6d1a2b32b642-S0"; | ||
private final String taskId = "http-ports-static-assigned-to-31002.0f732069-a1f2-11e7-97e0-0242ac110006"; | ||
private final String workDir = "/var/lib/mesos/agent-3039938407"; | ||
private final String frameworkId = "de09c926-7be6-47c6-ab9a-6d1a2b32b642-0000"; | ||
private final String runId = "fd7f7182-5ee8-47fc-a1c4-6928aeb1f769"; | ||
private final String agentServiceURL = "http://172.17.0.7:5051"; | ||
|
||
private final String PATH_FORMAT = "%s/slaves/%s/frameworks/%s/executors/%s/runs/%s"; | ||
private final String executorDirectory = String.format(PATH_FORMAT, workDir, slaveId, frameworkId, taskId, runId); | ||
|
||
private final String STDOUT_URL = "http://172.17.0.7:5051" + | ||
"/files/download?path=" + | ||
"%2Fvar%2Flib%2Fmesos" + | ||
"%2Fagent-3039938407" + | ||
"%2Fslaves%2Fde09c926-7be6-47c6-ab9a-6d1a2b32b642-S0" + | ||
"%2Fframeworks%2Fde09c926-7be6-47c6-ab9a-6d1a2b32b642-0000" + | ||
"%2Fexecutors%2Fhttp-ports-static-assigned-to-31002.0f732069-a1f2-11e7-97e0-0242ac110006" + | ||
"%2Fruns%2Ffd7f7182-5ee8-47fc-a1c4-6928aeb1f769" + | ||
"%2Fstdout"; | ||
|
||
private final String STDERR_URL = "http://172.17.0.7:5051" + | ||
"/files/download?path=" + | ||
"%2Fvar%2Flib%2Fmesos" + | ||
"%2Fagent-3039938407" + | ||
"%2Fslaves%2Fde09c926-7be6-47c6-ab9a-6d1a2b32b642-S0" + | ||
"%2Fframeworks%2Fde09c926-7be6-47c6-ab9a-6d1a2b32b642-0000" + | ||
"%2Fexecutors%2Fhttp-ports-static-assigned-to-31002.0f732069-a1f2-11e7-97e0-0242ac110006" + | ||
"%2Fruns%2Ffd7f7182-5ee8-47fc-a1c4-6928aeb1f769" + | ||
"%2Fstderr"; | ||
|
||
private ByteArrayOutputStream outputStream; | ||
|
||
private PrintStream ps; | ||
|
||
private ClusterRepository repository; | ||
|
||
private Downloader downloader; | ||
|
||
private State masterState; | ||
|
||
private State agentState; | ||
|
||
@Before | ||
public void initTest() throws URISyntaxException { | ||
outputStream = new ByteArrayOutputStream(); | ||
ps = new PrintStream(outputStream, true); | ||
|
||
masterState = generateMasterState(); | ||
agentState = generateAgentState(); | ||
|
||
MesosMasterContainer master = mock(MesosMasterContainer.class); | ||
when(master.getState()).thenReturn(masterState); | ||
|
||
MesosAgentContainer agent = mock(MesosAgentContainer.class); | ||
when(agent.getState()).thenReturn(agentState); | ||
when(agent.getServiceUrl()).thenReturn(new URI(agentServiceURL)); | ||
|
||
MesosCluster mesosCluster = mock(MesosCluster.class); | ||
when(mesosCluster.getMaster()).thenReturn(master); | ||
when(mesosCluster.getAgents()).thenReturn(Collections.singletonList(agent)); | ||
|
||
repository = mock(ClusterRepository.class); | ||
when(repository.loadCluster(any(MesosClusterFactory.class))).thenReturn(mesosCluster); | ||
|
||
downloader = mock(Downloader.class); | ||
when(downloader.getFileContentAsString(STDOUT_URL)).thenReturn("stdout file content"); | ||
when(downloader.getFileContentAsString(STDERR_URL)).thenReturn("stderr file content"); | ||
} | ||
|
||
@Test | ||
public void TestStdout() throws UnsupportedEncodingException, URISyntaxException { | ||
// Given | ||
CommandLogs commandLogs = new CommandLogs(ps); | ||
commandLogs.setRepository(repository); | ||
commandLogs.setDownloader(downloader); | ||
commandLogs.taskId = taskId; | ||
|
||
// When | ||
commandLogs.execute(); | ||
|
||
// Then | ||
String result = outputStream.toString("UTF-8"); | ||
assertEquals( | ||
"[minimesos] Fetching 'stdout' of task 'http-ports-static-assigned-to-31002.0f732069-a1f2-11e7-97e0-0242ac110006'\n\n" + | ||
"stdout file content\n", | ||
result); | ||
|
||
} | ||
|
||
@Test | ||
public void TestUnexistingTask() throws UnsupportedEncodingException, URISyntaxException { | ||
// Given | ||
CommandLogs commandLogs = new CommandLogs(ps); | ||
commandLogs.setRepository(repository); | ||
commandLogs.setDownloader(downloader); | ||
commandLogs.taskId = "doesn't exist"; | ||
|
||
// When | ||
commandLogs.execute(); | ||
|
||
// Then | ||
String result = outputStream.toString("UTF-8"); | ||
assertEquals("Cannot find task: 'doesn't exist'\n", result); | ||
|
||
} | ||
|
||
@Test | ||
public void TestStderr() throws UnsupportedEncodingException, URISyntaxException { | ||
// Given | ||
CommandLogs commandLogs = new CommandLogs(ps); | ||
commandLogs.setRepository(repository); | ||
commandLogs.setDownloader(downloader); | ||
commandLogs.taskId = taskId; | ||
commandLogs.stderr = true; | ||
|
||
// When | ||
commandLogs.execute(); | ||
|
||
// Then | ||
String result = outputStream.toString("UTF-8"); | ||
assertEquals( | ||
"[minimesos] Fetching 'stderr' of task 'http-ports-static-assigned-to-31002.0f732069-a1f2-11e7-97e0-0242ac110006'\n\n" + | ||
"stderr file content\n", | ||
result); | ||
} | ||
|
||
private State generateAgentState() { | ||
State state = new State(); | ||
state.setId(slaveId); | ||
|
||
Framework marathon = new Framework(); | ||
marathon.setName("marathon"); | ||
marathon.setId(frameworkId); | ||
|
||
Executor executor = new Executor(); | ||
executor.setDirectory(executorDirectory); | ||
executor.setId(taskId); | ||
ArrayList<Executor> executors = new ArrayList<>(); | ||
executors.add(executor); | ||
marathon.setExecutors(executors); | ||
|
||
ArrayList<Framework> frameworks = new ArrayList<>(); | ||
frameworks.add(marathon); | ||
state.setFrameworks(frameworks); | ||
|
||
return state; | ||
} | ||
|
||
private State generateMasterState() { | ||
State state = new State(); | ||
Framework marathon = new Framework(); | ||
marathon.setName("marathon"); | ||
|
||
Task task = new Task(); | ||
task.setName("weave-scope"); | ||
task.setState("TASK_RUNNING"); | ||
task.setId(taskId); | ||
task.setSlaveId(slaveId); | ||
task.setFrameworkId(frameworkId); | ||
task.setExecutorId(""); | ||
|
||
Port port = new Port(); | ||
port.setNumber(4040); | ||
|
||
Ports ports = new Ports(); | ||
ports.setPorts(singletonList(port)); | ||
|
||
Discovery discovery = new Discovery(); | ||
discovery.setPorts(ports); | ||
|
||
task.setDiscovery(discovery); | ||
|
||
ArrayList<Task> tasks = new ArrayList<>(); | ||
tasks.add(task); | ||
|
||
marathon.setTasks(tasks); | ||
|
||
ArrayList<Framework> frameworks = new ArrayList<>(); | ||
frameworks.add(marathon); | ||
state.setFrameworks(frameworks); | ||
|
||
return state; | ||
} | ||
} |
150 changes: 150 additions & 0 deletions
150
cli/src/main/java/com/containersol/minimesos/main/CommandLogs.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package com.containersol.minimesos.main; | ||
|
||
import com.beust.jcommander.Parameter; | ||
import com.beust.jcommander.Parameters; | ||
import com.containersol.minimesos.MinimesosException; | ||
import com.containersol.minimesos.cluster.ClusterRepository; | ||
import com.containersol.minimesos.cluster.MesosAgent; | ||
import com.containersol.minimesos.cluster.MesosCluster; | ||
import com.containersol.minimesos.mesos.MesosClusterContainersFactory; | ||
import com.containersol.minimesos.state.Executor; | ||
import com.containersol.minimesos.state.Framework; | ||
import com.containersol.minimesos.state.State; | ||
import com.containersol.minimesos.state.Task; | ||
import com.containersol.minimesos.util.Downloader; | ||
import org.apache.http.client.utils.URIBuilder; | ||
|
||
import java.io.PrintStream; | ||
import java.net.URI; | ||
import java.net.URISyntaxException; | ||
|
||
import static org.apache.commons.lang.StringUtils.isNotBlank; | ||
import static org.apache.commons.lang.StringUtils.isBlank; | ||
|
||
@Parameters(separators = "=", commandDescription = "Fetches the stdout logs of the specified task") | ||
public class CommandLogs implements Command { | ||
|
||
private PrintStream output = System.out; // NOSONAR | ||
|
||
private ClusterRepository repository = new ClusterRepository(); | ||
|
||
private Downloader downloader = new Downloader(); | ||
|
||
@Parameter(names = "--task", description = "Substring of a task ID", required = true) | ||
String taskId = null; | ||
|
||
@Parameter(names = "--stderr", description = "Fetch the stderr logs instead of stdout") | ||
Boolean stderr = false; | ||
|
||
public CommandLogs(PrintStream output) { | ||
this.output = output; | ||
} | ||
|
||
public CommandLogs() { | ||
//NOSONAR | ||
} | ||
|
||
@Override | ||
public boolean validateParameters() { | ||
return isNotBlank(taskId); | ||
} | ||
|
||
@Override | ||
public String getName() { | ||
return "logs"; | ||
} | ||
|
||
@Override | ||
public void execute() { | ||
MesosCluster cluster = repository.loadCluster(new MesosClusterContainersFactory()); | ||
if (cluster == null) { | ||
output.println("Minimesos cluster is not running"); | ||
return; | ||
} | ||
|
||
State masterState = cluster.getMaster().getState(); | ||
Task task = findTask(masterState, taskId); | ||
if (task == null) { | ||
output.println(String.format("Cannot find task: '%s'", taskId)); | ||
return; | ||
} | ||
|
||
MesosAgent agent = findAgent(cluster, task.getSlaveId()); | ||
if (agent == null) { | ||
output.println(String.format("Cannot find agent: '%s'", task.getSlaveId())); | ||
return; | ||
} | ||
|
||
|
||
String filename = stderr ? "stderr" : "stdout"; | ||
output.println(String.format("[minimesos] Fetching '%s' of task '%s'\n", filename, task.getId())); | ||
URI fileUrl = getFileUrl(agent, task, filename); | ||
String content = downloader.getFileContentAsString(fileUrl.toString()); | ||
output.println(content); | ||
} | ||
|
||
public void setRepository(ClusterRepository repository) { | ||
this.repository = repository; | ||
} | ||
|
||
void setDownloader(Downloader downloader) { | ||
this.downloader = downloader; | ||
} | ||
|
||
private Task findTask(State state, String taskId) { | ||
for (Framework framework : state.getFrameworks()) { | ||
for (Task task: framework.getTasks()) { | ||
if (task.getId().contains(taskId)) { | ||
return task; | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private MesosAgent findAgent(MesosCluster cluster, String slaveId) { | ||
for (MesosAgent agent : cluster.getAgents()) { | ||
State agentState = agent.getState(); | ||
if (agentState.getId().equals(slaveId)) { | ||
return agent; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private URI getFileUrl(MesosAgent agent, Task task, String filename) throws MinimesosException { | ||
Executor executor = findExecutor(agent, task); | ||
if (executor == null) { | ||
throw new MinimesosException(String.format("Cannot find executor: '%s'", taskId)); | ||
} | ||
String path = executor.getDirectory(); | ||
URIBuilder uriBuilder = new URIBuilder(agent.getServiceUrl()) | ||
.setPath("/files/download") | ||
.addParameter("path", path + "/" + filename); | ||
URI sandboxUrl = null; | ||
try { | ||
sandboxUrl = uriBuilder.build(); | ||
} catch (URISyntaxException e) { | ||
throw new MinimesosException(e.getMessage()); | ||
} | ||
return sandboxUrl; | ||
} | ||
|
||
private Executor findExecutor(MesosAgent agent, Task task) { | ||
String executorId = task.getExecutorId(); | ||
if (isBlank(executorId)) { // if executorId is empty, try with the taskId | ||
executorId = task.getId(); | ||
} | ||
for (Framework framework : agent.getState().getFrameworks()) { | ||
if (framework.getId().equals(task.getFrameworkId())) { | ||
for (Executor executor : framework.getExecutors()) { | ||
if (executor.getId().equals(executorId)) { | ||
return executor; | ||
} | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.