CODENVY-1271: fix agent launching in some cases
Fix AbstractAgentLauncher. Code cleanup. Signed-off-by: Alexander Garagatyi <agaragatyi@codenvy.com>6.19.x
parent
185de42cd0
commit
1eceaebe75
|
|
@ -127,14 +127,12 @@ public class CommandLine {
|
|||
public String toString() {
|
||||
final String[] str = asArray();
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
// sb.append('\'');
|
||||
for (String s : str) {
|
||||
if (sb.length() > 1) {
|
||||
sb.append(' ');
|
||||
}
|
||||
sb.append(s);
|
||||
}
|
||||
// sb.append('\'');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@
|
|||
<configuration>
|
||||
<target unless="skipTests">
|
||||
<exec dir="${project.build.directory}/${go.workspace.name}/src/github.com/eclipse/che/exec-agent" executable="go" failonerror="true">
|
||||
<env key="GOPATH" value="${project.build.directory}/${go.workspace.name}"/>
|
||||
<env key="GOPATH" value="${project.build.directory}/${go.workspace.name}" />
|
||||
<arg value="test" />
|
||||
<arg value="-v" />
|
||||
<arg value="./..." />
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public class LogMessage {
|
|||
private final Type type;
|
||||
private final String content;
|
||||
|
||||
LogMessage(Type type, String content) {
|
||||
public LogMessage(Type type, String content) {
|
||||
this.type = type;
|
||||
this.content = content;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.machine.Command;
|
||||
import org.eclipse.che.api.core.model.machine.Machine;
|
||||
import org.eclipse.che.api.core.model.machine.MachineSource;
|
||||
|
|
@ -285,7 +286,8 @@ public class DockerInstance extends AbstractInstance {
|
|||
docker.removeContainer(RemoveContainerParams.create(container)
|
||||
.withRemoveVolumes(true)
|
||||
.withForce(true));
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | ServerException e) {
|
||||
LOG.error(e.getLocalizedMessage(), e);
|
||||
throw new MachineException(e.getLocalizedMessage());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public class DockerProcess extends AbstractMachineProcess implements InstancePro
|
|||
if (started) {
|
||||
throw new ConflictException("Process already started.");
|
||||
}
|
||||
started = true;
|
||||
// Trap is invoked when bash session ends. Here we kill all sub-processes of shell and remove pid-file.
|
||||
final String trap = format("trap '[ -z \"$(jobs -p)\" ] || kill $(jobs -p); [ -e %1$s ] && rm %1$s' EXIT", pidFilePath);
|
||||
// 'echo' saves shell pid in file, then run command
|
||||
|
|
@ -106,7 +107,6 @@ public class DockerProcess extends AbstractMachineProcess implements InstancePro
|
|||
throw new MachineException(format("Error occurs while initializing command %s in docker container %s: %s",
|
||||
Arrays.toString(command), container, e.getMessage()), e);
|
||||
}
|
||||
started = true;
|
||||
try {
|
||||
docker.startExec(StartExecParams.create(exec.getId()), output == null ? null : new LogMessagePrinter(output));
|
||||
} catch (IOException e) {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ package org.eclipse.che.plugin.docker.machine.local;
|
|||
|
||||
import com.google.inject.assistedinject.Assisted;
|
||||
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.plugin.docker.client.DockerConnectorConfiguration;
|
||||
import org.eclipse.che.plugin.docker.machine.node.DockerNode;
|
||||
import org.eclipse.che.plugin.docker.machine.node.WorkspaceFolderPathProvider;
|
||||
|
|
@ -29,7 +29,6 @@ import java.io.IOException;
|
|||
*/
|
||||
public class LocalDockerNode implements DockerNode {
|
||||
|
||||
private final String workspaceFolder;
|
||||
private final String host;
|
||||
|
||||
@Inject
|
||||
|
|
@ -37,25 +36,16 @@ public class LocalDockerNode implements DockerNode {
|
|||
WorkspaceFolderPathProvider workspaceFolderNodePathProvider,
|
||||
DockerConnectorConfiguration dockerConnectorConfiguration) throws IOException {
|
||||
|
||||
workspaceFolder = workspaceFolderNodePathProvider.getPath(workspaceId);
|
||||
// TODO investigate whether we can remove that after abandonment of native Che
|
||||
workspaceFolderNodePathProvider.getPath(workspaceId);
|
||||
host = dockerConnectorConfiguration.getDockerHost();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindWorkspace() throws MachineException {
|
||||
|
||||
}
|
||||
public void bindWorkspace() throws ServerException {}
|
||||
|
||||
@Override
|
||||
public void unbindWorkspace() throws MachineException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProjectsFolder() {
|
||||
return workspaceFolder;
|
||||
}
|
||||
|
||||
public void unbindWorkspace() throws ServerException {}
|
||||
|
||||
@Override
|
||||
public String getHost() {
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ public class LocalWorkspaceFolderPathProvider implements WorkspaceFolderPathProv
|
|||
}
|
||||
} else {
|
||||
try {
|
||||
// TODO we should not create folders in this provider
|
||||
Files.createDirectories(folder);
|
||||
} catch (AccessDeniedException e) {
|
||||
throw new IOException(
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.plugin.docker.machine.node;
|
||||
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.machine.server.spi.InstanceNode;
|
||||
|
||||
/**
|
||||
|
|
@ -22,21 +22,18 @@ public interface DockerNode extends InstanceNode {
|
|||
/**
|
||||
* Bind the whole workspace on the Node.
|
||||
*
|
||||
* @throws MachineException
|
||||
* @throws ServerException
|
||||
* if error occurs on binding
|
||||
*/
|
||||
void bindWorkspace() throws MachineException;
|
||||
void bindWorkspace() throws ServerException;
|
||||
|
||||
/**
|
||||
* Unbind the workspace on Node.
|
||||
*
|
||||
* @throws MachineException
|
||||
* @throws ServerException
|
||||
* if error occurs on binding
|
||||
*/
|
||||
void unbindWorkspace() throws MachineException;
|
||||
|
||||
@Override
|
||||
String getProjectsFolder();
|
||||
void unbindWorkspace() throws ServerException;
|
||||
|
||||
@Override
|
||||
String getHost();
|
||||
|
|
|
|||
|
|
@ -121,7 +121,6 @@ public class MachineProviderImplTest {
|
|||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
when(dockerConnectorConfiguration.getDockerHostIp()).thenReturn("123.123.123.123");
|
||||
when(dockerNode.getProjectsFolder()).thenReturn("/tmp/projects");
|
||||
|
||||
provider = spy(new MachineProviderBuilder().build());
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,11 @@
|
|||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.everrest</groupId>
|
||||
<artifactId>everrest-assured</artifactId>
|
||||
|
|
|
|||
|
|
@ -18,16 +18,17 @@ import org.eclipse.che.api.core.ServerException;
|
|||
import org.eclipse.che.api.core.model.machine.Command;
|
||||
import org.eclipse.che.api.core.util.AbstractLineConsumer;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler;
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.machine.server.model.impl.CommandImpl;
|
||||
import org.eclipse.che.api.machine.server.spi.Instance;
|
||||
import org.eclipse.che.api.machine.server.spi.InstanceProcess;
|
||||
import org.eclipse.che.commons.lang.concurrent.LoggingUncaughtExceptionHandler;
|
||||
import org.eclipse.che.commons.lang.concurrent.ThreadLocalPropagateContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
|
|
@ -97,18 +98,20 @@ public abstract class AbstractAgentLauncher implements AgentLauncher {
|
|||
}
|
||||
|
||||
|
||||
protected InstanceProcess start(final Instance machine, final Agent agent) throws ServerException {
|
||||
final Command command = new CommandImpl(agent.getId(), agent.getScript(), "agent");
|
||||
final InstanceProcess process = machine.createProcess(command, null);
|
||||
final LineConsumer lineConsumer = new AbstractLineConsumer() {
|
||||
protected InstanceProcess start(Instance machine, Agent agent) throws ServerException {
|
||||
Command command = new CommandImpl(agent.getId(), agent.getScript(), "agent");
|
||||
InstanceProcess process = machine.createProcess(command, null);
|
||||
LineConsumer lineConsumer = new AbstractLineConsumer() {
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {
|
||||
machine.getLogger().writeLine(line);
|
||||
}
|
||||
};
|
||||
|
||||
CountDownLatch countDownLatch = new CountDownLatch(1);
|
||||
executor.execute(ThreadLocalPropagateContext.wrap(() -> {
|
||||
try {
|
||||
countDownLatch.countDown();
|
||||
process.start(lineConsumer);
|
||||
} catch (ConflictException | MachineException e) {
|
||||
try {
|
||||
|
|
@ -122,6 +125,12 @@ public abstract class AbstractAgentLauncher implements AgentLauncher {
|
|||
}
|
||||
}
|
||||
}));
|
||||
try {
|
||||
// ensure that code inside of task submitted to executor is called before end of this method
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
|
||||
return process;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,275 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2012-2016 Codenvy, S.A.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Codenvy, S.A. - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.che.api.agent.server.launcher;
|
||||
|
||||
import org.eclipse.che.api.agent.shared.model.Agent;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.machine.server.model.impl.CommandImpl;
|
||||
import org.eclipse.che.api.machine.server.spi.Instance;
|
||||
import org.eclipse.che.api.machine.server.spi.InstanceProcess;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.mockito.testng.MockitoTestNGListener;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.atLeast;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.verifyZeroInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
@Listeners(MockitoTestNGListener.class)
|
||||
public class AbstractAgentLauncherTest {
|
||||
@Mock
|
||||
private Instance machine;
|
||||
@Mock
|
||||
private Agent agent;
|
||||
@Mock
|
||||
private InstanceProcess process;
|
||||
@Mock
|
||||
private AgentLaunchingChecker agentChecker;
|
||||
|
||||
private AbstractAgentLauncher launcher;
|
||||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
launcher = spy(new TestAgentLauncher(500, 100, agentChecker));
|
||||
|
||||
when(agent.getScript()).thenReturn("script content");
|
||||
doReturn(process).when(launcher).start(any(Instance.class), any(Agent.class));
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class))).thenReturn(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToCheckAgentState() throws Exception {
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
verify(agentChecker).isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doNothingIfAgentScriptIsNull() throws Exception {
|
||||
// given
|
||||
when(agent.getScript()).thenReturn(null);
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
verify(launcher, never()).start(any(Instance.class), any(Agent.class));
|
||||
verify(agent).getScript();
|
||||
verifyNoMoreInteractions(agent);
|
||||
verifyZeroInteractions(machine);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doNothingIfAgentScriptIsEmpty() throws Exception {
|
||||
// given
|
||||
when(agent.getScript()).thenReturn("");
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
verify(launcher, never()).start(any(Instance.class), any(Agent.class));
|
||||
verify(agent).getScript();
|
||||
verifyNoMoreInteractions(agent);
|
||||
verifyZeroInteractions(machine);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCheckIfAgentIsLaunchedUntilItIsLaunched() throws Exception {
|
||||
// given
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class))).thenReturn(false)
|
||||
.thenReturn(false)
|
||||
.thenReturn(false)
|
||||
.thenReturn(false)
|
||||
.thenReturn(true);
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
verify(agentChecker, times(5)).isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ServerException.class, expectedExceptionsMessageRegExp = "Fail launching agent .*. Workspace ID:.*")
|
||||
public void shouldNotCheckIfAgentIsLaunchedMoreThanAgentMaxStartTime() throws Exception {
|
||||
// given
|
||||
launcher = spy(new TestAgentLauncher(200, 100, agentChecker));
|
||||
doReturn(process).when(launcher).start(any(Instance.class), any(Agent.class));
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class))).thenReturn(false)
|
||||
.thenReturn(false)
|
||||
.thenReturn(false)
|
||||
.thenReturn(false)
|
||||
.thenReturn(true);
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
// ensure that isLaunched was called several times and then max pinging time was exceeded
|
||||
verify(agentChecker, atLeast(2)).isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotCheckMoreFrequentThanAgentCheckDelay() throws Exception {
|
||||
// given
|
||||
launcher = spy(new TestAgentLauncher(200, 10, agentChecker));
|
||||
doReturn(process).when(launcher).start(any(Instance.class), any(Agent.class));
|
||||
// record time of each check of agent state
|
||||
ArrayList<Long> checkTimestamps = new ArrayList<>(5);
|
||||
Answer<Boolean> recordTimestampAndReturnFalse = invocationOnMock -> {
|
||||
checkTimestamps.add(System.currentTimeMillis());
|
||||
return false;
|
||||
};
|
||||
Answer<Boolean> recordTimestampAndReturnTrue = invocationOnMock -> {
|
||||
checkTimestamps.add(System.currentTimeMillis());
|
||||
return true;
|
||||
};
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class))).thenAnswer(recordTimestampAndReturnFalse)
|
||||
.thenAnswer(recordTimestampAndReturnFalse)
|
||||
.thenAnswer(recordTimestampAndReturnFalse)
|
||||
.thenAnswer(recordTimestampAndReturnFalse)
|
||||
.thenAnswer(recordTimestampAndReturnTrue);
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
// ensure that each check was done after required timeout
|
||||
for (int i = 1; i < checkTimestamps.size(); i++) {
|
||||
assertTrue(checkTimestamps.get(i) - checkTimestamps.get(i - 1) >= 10);
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ServerException.class, expectedExceptionsMessageRegExp = "agent launcher test exception")
|
||||
public void shouldThrowServerExceptionIfMachineExceptionIsThrownByAgentCheck() throws Exception {
|
||||
// given
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class)))
|
||||
.thenThrow(new MachineException("agent launcher test exception"));
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldSetBackInterruptedFlagIfThreadWasInterrupted() throws Exception {
|
||||
try {
|
||||
// imitate interruption of launching thread
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class))).thenAnswer(invocationOnMock -> {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
});
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
} catch (ServerException e) {
|
||||
// Ensure that after exiting launcher thread is still in interrupted state
|
||||
assertTrue(Thread.currentThread().isInterrupted());
|
||||
} finally {
|
||||
// cleanup interrupted state
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ServerException.class, expectedExceptionsMessageRegExp = "Launching agent .* is interrupted")
|
||||
public void shouldThrowServerExceptionIfAgentCheckWasInterrupted() throws Exception {
|
||||
try {
|
||||
when(agentChecker.isLaunched(any(Agent.class),
|
||||
any(InstanceProcess.class),
|
||||
any(Instance.class))).thenAnswer(invocationOnMock -> {
|
||||
Thread.currentThread().interrupt();
|
||||
return false;
|
||||
});
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
} finally {
|
||||
// cleanup interrupted state
|
||||
Thread.interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldStartMachineProcessWithAgentScriptExecution() throws Exception {
|
||||
// given
|
||||
String agentId = "testAgentId";
|
||||
String agentScript = "testAgentScript";
|
||||
when(agent.getId()).thenReturn(agentId);
|
||||
when(agent.getScript()).thenReturn(agentScript);
|
||||
when(launcher.start(any(Instance.class), any(Agent.class))).thenCallRealMethod();
|
||||
|
||||
// when
|
||||
launcher.launch(machine, agent);
|
||||
|
||||
// then
|
||||
verify(machine).createProcess(eq(new CommandImpl(agentId, agentScript, "agent")), eq(null));
|
||||
}
|
||||
|
||||
private static class TestAgentLauncher extends AbstractAgentLauncher {
|
||||
public TestAgentLauncher(long agentMaxStartTimeMs,
|
||||
long agentPingDelayMs,
|
||||
AgentLaunchingChecker agentLaunchingChecker) {
|
||||
super(agentMaxStartTimeMs, agentPingDelayMs, agentLaunchingChecker);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected InstanceProcess start(Instance machine, Agent agent) throws ServerException {
|
||||
return super.start(machine, agent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAgentId() {
|
||||
return "testAgentId";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMachineType() {
|
||||
return "testMachineType";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2012-2016 Codenvy, S.A.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Contributors:
|
||||
# Codenvy, S.A. - initial API and implementation
|
||||
#
|
||||
|
||||
CHE_PATH=/home/tolusha/java/env-projects/che/assembly/assembly-main/target/eclipse-che-4.8.0-SNAPSHOT/eclipse-che-4.8.0-SNAPSHOT/bin
|
||||
HOST_URL=localhost:8080
|
||||
TEST_LOG="agents-test.log"
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2012-2016 Codenvy, S.A.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Contributors:
|
||||
# Codenvy, S.A. - initial API and implementation
|
||||
#
|
||||
|
||||
. ./config.sh
|
||||
|
||||
trap cleanUp EXIT
|
||||
|
||||
cleanUp() {
|
||||
${CHE_PATH}/che.sh stop
|
||||
}
|
||||
|
||||
printAndLog() {
|
||||
echo $@
|
||||
log $@
|
||||
}
|
||||
|
||||
logStartCommand() {
|
||||
log
|
||||
log "=== [ "`date`" ] COMMAND STARTED: "$@
|
||||
}
|
||||
|
||||
logEndCommand() {
|
||||
log "=================================== COMMAND COMPLETED: "$@
|
||||
log
|
||||
}
|
||||
|
||||
log() {
|
||||
echo "TEST: "$@ >> ${TEST_LOG}
|
||||
}
|
||||
|
||||
fetchJsonParameter() {
|
||||
OUTPUT=`echo ${OUTPUT} | sed 's/.*"'$1'"\s*:\s*"\([^"]*\)*".*/\1/'`
|
||||
}
|
||||
|
||||
# --method={POST|GET|...}
|
||||
# --content-type=...
|
||||
# --cookie=...
|
||||
# --body=...
|
||||
# --url=...
|
||||
# --output-http-code
|
||||
# --verbose
|
||||
doHttpRequest() {
|
||||
for var in "$@"; do
|
||||
if [[ "$var" =~ --content-type=.+ ]]; then
|
||||
CONTENT_TYPE_OPTION=`echo "-H \"Content-Type: $var\"" | sed -e "s/--content-type=//g"`
|
||||
|
||||
elif [[ "$var" =~ --body=.+ ]]; then
|
||||
local BODY_OPTION=`echo "-d '$var'" | sed -e "s/--body=//g"`
|
||||
|
||||
elif [[ "$var" =~ --url=.+ ]]; then
|
||||
local URL=`echo "'$var'" | sed -e "s/--url=//g"`
|
||||
|
||||
elif [[ "$var" =~ --method=.+ ]]; then
|
||||
local METHOD_OPTION=`echo "-X $var" | sed -e "s/--method=//g"`
|
||||
|
||||
elif [[ "$var" == "--output-http-code" ]]; then
|
||||
local OUTPUT_HTTP_CODE_OPTION="-o /dev/null -w \"%{http_code}\""
|
||||
|
||||
elif [[ "$var" == "--verbose" ]]; then
|
||||
local VERBOSE_OPTION="-v"
|
||||
|
||||
elif [[ "$var" =~ --cookie=.+ ]]; then
|
||||
local COOKIE_OPTION=$(echo "-H \"Cookie: session-access-key=$var\"" | sed -e "s/--cookie=//g")
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
local COMMAND="curl -s $VERBOSE_OPTION $OUTPUT_HTTP_CODE_OPTION $CONTENT_TYPE_OPTION $COOKIE_OPTION $BODY_OPTION $METHOD_OPTION $URL"
|
||||
|
||||
logStartCommand $COMMAND
|
||||
|
||||
OUTPUT=$(eval $COMMAND)
|
||||
EXIT_CODE=$?
|
||||
log ${OUTPUT}
|
||||
|
||||
logEndCommand "curl"
|
||||
}
|
||||
|
||||
doPost() {
|
||||
doHttpRequest --method=POST \
|
||||
--content-type=$1 \
|
||||
--body="$2" \
|
||||
--url=$3 \
|
||||
--cookie=$4
|
||||
}
|
||||
|
||||
doGet() {
|
||||
doHttpRequest --method=GET \
|
||||
--url=$1
|
||||
}
|
||||
|
||||
doDelete() {
|
||||
doHttpRequest --method=DELETE \
|
||||
--url=$1
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
|
||||
Copyright (c) 2012-2016 Codenvy, S.A.
|
||||
All rights reserved. This program and the accompanying materials
|
||||
are made available under the terms of the Eclipse Public License v1.0
|
||||
which accompanies this distribution, and is available at
|
||||
http://www.eclipse.org/legal/epl-v10.html
|
||||
|
||||
Contributors:
|
||||
Codenvy, S.A. - initial API and implementation
|
||||
|
||||
-->
|
||||
<configuration>
|
||||
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<root level="ERROR">
|
||||
<appender-ref ref="stdout"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright (c) 2012-2016 Codenvy, S.A.
|
||||
# All rights reserved. This program and the accompanying materials
|
||||
# are made available under the terms of the Eclipse Public License v1.0
|
||||
# which accompanies this distribution, and is available at
|
||||
# http://www.eclipse.org/legal/epl-v10.html
|
||||
#
|
||||
# Contributors:
|
||||
# Codenvy, S.A. - initial API and implementation
|
||||
#
|
||||
|
||||
. ./lib.sh
|
||||
|
||||
|
||||
${CHE_PATH}/che.sh --debug start
|
||||
sleep 20s
|
||||
|
||||
DOCKER_CONTENT=("FROM fedora:23\nCMD tail -f /dev/null"
|
||||
"FROM ubuntu:16.04\nCMD tail -f /dev/null"
|
||||
"FROM ubuntu:14.04\nCMD tail -f /dev/null"
|
||||
"FROM centos:7\nCMD tail -f /dev/null"
|
||||
"FROM opensuse:13.2\nCMD tail -f /dev/null"
|
||||
"FROM debian:8\nCMD tail -f /dev/null");
|
||||
|
||||
waitStatus() {
|
||||
WORKSPACE_ID=$1
|
||||
STATUS=$2
|
||||
ATTEMPTS=200
|
||||
|
||||
for ((j = 0; j < ${ATTEMPTS}; j++))
|
||||
do
|
||||
doGet "http://"${HOST_URL}"/api/workspace/"${WORKSPACE_ID}
|
||||
if echo ${OUTPUT} | grep -qi "\"id\":\"${WORKSPACE_ID}\",\"status\":\"${STATUS}\""; then
|
||||
echo ${STATUS}
|
||||
break
|
||||
fi
|
||||
sleep 5s
|
||||
done
|
||||
}
|
||||
|
||||
validateRunningProcess() {
|
||||
WORKSPACE_ID=$1
|
||||
PROCESS=$2
|
||||
|
||||
CONTAINER_ID=$(docker ps -aqf "name="${WORKSPACE_ID})
|
||||
printAndLog "Container ID "${CONTAINER_ID}" validate "${PROCESS}
|
||||
|
||||
PID=$(docker exec -ti ${CONTAINER_ID} ps -fC ${PROCESS})
|
||||
if [ "${PID}" = "" ]; then
|
||||
printAndLog "RESULT: FAILED. Process "${PROCESS}" not found"
|
||||
fi
|
||||
}
|
||||
|
||||
deleteWorkspace() {
|
||||
WORKSPACE_ID=$1
|
||||
|
||||
doDelete "http://"${HOST_URL}"/api/workspace/"${WORKSPACE_ID}"/runtime"
|
||||
STATUS=$(waitStatus ${WORKSPACE_ID} "STOPPED")
|
||||
if echo ${STATUS} | grep -qi "STOPPED"; then
|
||||
doDelete "http://"${HOST_URL}"/api/workspace/"${WORKSPACE_ID}
|
||||
sleep 1m
|
||||
else
|
||||
printAndLog "ERROR. Workspace "${WORKSPACE_ID}" can't be stopped"
|
||||
fi
|
||||
}
|
||||
|
||||
for ((i = 0; i < ${#DOCKER_CONTENT[@]}; i++))
|
||||
do
|
||||
CONTENT="${DOCKER_CONTENT[$i]}"
|
||||
printAndLog
|
||||
printAndLog "####################################################################"
|
||||
printAndLog "Creating workspace with recipe: \""${CONTENT}"\""
|
||||
printAndLog "####################################################################"
|
||||
|
||||
NAME=$(date +%s | sha256sum | base64 | head -c 5)
|
||||
doPost "application/json" "{\"name\":\"${NAME}\",\"projects\":[],\"defaultEnv\":\"${NAME}\",\"description\":null,\"environments\":[{\"name\":\"${NAME}\",\"recipe\":null,\"machineConfigs\":[{\"name\":\"ws-machine\",\"limits\":{\"ram\":1000},\"type\":\"docker\",\"source\":{\"type\":\"dockerfile\",\"content\":\"${CONTENT}\"},\"dev\":true}]}]}" "http://"${HOST_URL}"/api/workspace?account="
|
||||
fetchJsonParameter "id"
|
||||
WORKSPACE_ID=${OUTPUT}
|
||||
|
||||
printAndLog "Starting workspace: "${WORKSPACE_ID}
|
||||
doPost "application/json" "{}" "http://"${HOST_URL}"/api/workspace/"${WORKSPACE_ID}"/runtime?environment="${NAME}
|
||||
|
||||
STATUS=$(waitStatus ${WORKSPACE_ID} "RUNNING")
|
||||
if echo ${STATUS} | grep -qi "RUNNING"; then
|
||||
validateRunningProcess ${WORKSPACE_ID} "che-websocket-terminal"
|
||||
validateRunningProcess ${WORKSPACE_ID} "java"
|
||||
validateRunningProcess ${WORKSPACE_ID} "sshd"
|
||||
else
|
||||
printAndLog "RESULT: FAILED. Workspace not started."
|
||||
fi
|
||||
|
||||
deleteWorkspace ${WORKSPACE_ID}
|
||||
done
|
||||
|
|
@ -16,11 +16,6 @@ package org.eclipse.che.api.machine.server.spi;
|
|||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public interface InstanceNode {
|
||||
/**
|
||||
* Get path of folder on machine node with workspace fs
|
||||
*/
|
||||
String getProjectsFolder();
|
||||
|
||||
/**
|
||||
* Host of the server where machine is launched
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue