CHE-1368: rework machine's output/statuses events subscribing (#1600)
Rework output/status events of machine to be per workspace as a part of implementation of new multi-machine environments. Get rid of usage of machine manager in workspace service Refactor code of machine manager. Signed-off-by: Alexander Garagatyi <agaragatyi@codenvy.com>6.19.x
parent
58ca02cd73
commit
a27b62df9f
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* 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.core.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* No-op implementation of {@link LineConsumer}
|
||||
*
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public abstract class AbstractLineConsumer implements LineConsumer {
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* 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.core.util;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* No-op implementation of {@link MessageConsumer}
|
||||
*
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public class AbstractMessageConsumer<T> implements MessageConsumer<T> {
|
||||
@Override
|
||||
public void consume(T message) throws IOException {}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {}
|
||||
}
|
||||
|
|
@ -17,18 +17,11 @@ import java.io.IOException;
|
|||
* Consumes text line by line for analysing, writing, storing, etc.
|
||||
*
|
||||
* @author andrew00x
|
||||
* @see AbstractLineConsumer
|
||||
*/
|
||||
public interface LineConsumer extends Closeable {
|
||||
/** Consumes single line. */
|
||||
void writeLine(String line) throws IOException;
|
||||
|
||||
LineConsumer DEV_NULL = new LineConsumer() {
|
||||
@Override
|
||||
public void writeLine(String line) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
};
|
||||
LineConsumer DEV_NULL = new AbstractLineConsumer() {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
/*******************************************************************************
|
||||
* 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.core.util;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Consumes messages one by one for analysing, writing, storing, etc.
|
||||
*
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public interface MessageConsumer<T> extends Closeable {
|
||||
void consume(T message) throws IOException;
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.api.core.util;
|
||||
|
||||
import org.everrest.core.impl.provider.json.JsonUtils;
|
||||
import org.everrest.websockets.WSConnectionContext;
|
||||
import org.everrest.websockets.message.ChannelBroadcastMessage;
|
||||
import org.slf4j.Logger;
|
||||
|
|
@ -36,7 +35,7 @@ public class WebsocketLineConsumer implements LineConsumer {
|
|||
public void writeLine(String line) throws IOException {
|
||||
final ChannelBroadcastMessage bm = new ChannelBroadcastMessage();
|
||||
bm.setChannel(channel);
|
||||
bm.setBody(JsonUtils.getJsonString(line));
|
||||
bm.setBody(line);
|
||||
try {
|
||||
WSConnectionContext.sendMessage(bm);
|
||||
} catch (Exception e) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
/*******************************************************************************
|
||||
* 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.core.util;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Message consumer that sends messages to specified websocket channel
|
||||
*
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public class WebsocketMessageConsumer<T> extends AbstractMessageConsumer<T> {
|
||||
private static final Gson GSON = new GsonBuilder().disableHtmlEscaping().create();
|
||||
|
||||
private final LineConsumer messageSender;
|
||||
|
||||
public WebsocketMessageConsumer(String channel) {
|
||||
this.messageSender = new WebsocketLineConsumer(channel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void consume(T message) throws IOException {
|
||||
messageSender.writeLine(GSON.toJson(message));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* 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.core.model.machine;
|
||||
|
||||
/**
|
||||
* Represents log message from machine
|
||||
*
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public interface MachineLogMessage {
|
||||
/**
|
||||
* Content of log message
|
||||
*/
|
||||
String getContent();
|
||||
|
||||
/**
|
||||
* Machine name
|
||||
*/
|
||||
String getMachineName();
|
||||
}
|
||||
|
|
@ -10,9 +10,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.api.machine;
|
||||
|
||||
import com.google.gwt.json.client.JSONParser;
|
||||
import com.google.gwt.json.client.JSONString;
|
||||
|
||||
import org.eclipse.che.ide.websocket.Message;
|
||||
import org.eclipse.che.ide.websocket.rest.Unmarshallable;
|
||||
|
||||
|
|
@ -32,8 +29,7 @@ public class CommandOutputMessageUnmarshaller implements Unmarshallable<String>
|
|||
|
||||
@Override
|
||||
public void unmarshal(Message message) {
|
||||
final JSONString jsonString = JSONParser.parseStrict(message.getBody()).isString();
|
||||
payload = jsonString.stringValue();
|
||||
payload = message.getBody();
|
||||
|
||||
if (payload.startsWith("[STDOUT]")) {
|
||||
payload = payload.substring(9);
|
||||
|
|
|
|||
|
|
@ -10,9 +10,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.che.ide.api.machine;
|
||||
|
||||
import com.google.gwt.json.client.JSONParser;
|
||||
import com.google.gwt.json.client.JSONString;
|
||||
|
||||
import org.eclipse.che.ide.websocket.Message;
|
||||
import org.eclipse.che.ide.websocket.rest.Unmarshallable;
|
||||
|
||||
|
|
@ -26,9 +23,7 @@ public class OutputMessageUnmarshaller implements Unmarshallable<String> {
|
|||
|
||||
@Override
|
||||
public void unmarshal(Message message) {
|
||||
final JSONString jsonString = JSONParser.parseStrict(message.getBody()).isString();
|
||||
payload = jsonString.stringValue();
|
||||
|
||||
payload = message.getBody();
|
||||
if (payload.startsWith("[STDOUT]") || payload.startsWith("[STDERR]")) {
|
||||
payload = payload.substring(9);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
package org.eclipse.che.plugin.machine.ssh;
|
||||
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.core.util.AbstractLineConsumer;
|
||||
import org.eclipse.che.api.core.util.ListLineConsumer;
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.machine.server.model.impl.CommandImpl;
|
||||
|
|
@ -164,14 +164,11 @@ public class SshMachineImplTerminalLauncher implements MachineImplSpecificTermin
|
|||
null),
|
||||
null);
|
||||
|
||||
startTerminal.start(new LineConsumer() {
|
||||
startTerminal.start(new AbstractLineConsumer() {
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {
|
||||
machine.getLogger().writeLine("[Terminal] " + line);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ public class Constants {
|
|||
public static final String WSAGENT_WEBSOCKET_REFERENCE = "wsagent.websocket";
|
||||
public static final String WSAGENT_DEBUG_REFERENCE = "wsagent.debug";
|
||||
|
||||
public static final String LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL = "environment.output_channel";
|
||||
public static final String ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE = "workspace:%s:environment_output";
|
||||
public static final String LINK_REL_ENVIRONMENT_STATUS_CHANNEL = "environment.status_channel";
|
||||
public static final String ENVIRONMENT_STATUS_CHANNEL_TEMPLATE = "workspace:%s:machines_statuses";
|
||||
|
||||
public static final String TERMINAL_REFERENCE = "terminal";
|
||||
|
||||
public static final String WS_AGENT_PORT = "4401/tcp";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*******************************************************************************
|
||||
* 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.machine.shared.dto;
|
||||
|
||||
import org.eclipse.che.api.core.model.machine.MachineLogMessage;
|
||||
import org.eclipse.che.dto.shared.DTO;
|
||||
|
||||
/**
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
@DTO
|
||||
public interface MachineLogMessageDto extends MachineLogMessage {
|
||||
void setContent(String content);
|
||||
|
||||
MachineLogMessageDto withContent(String content);
|
||||
|
||||
void setMachineName(String machineName);
|
||||
|
||||
MachineLogMessageDto withMachineName(String machineName);
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ import com.google.common.annotations.VisibleForTesting;
|
|||
import com.google.common.base.Strings;
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
|
||||
import org.eclipse.che.api.core.ApiException;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.ForbiddenException;
|
||||
|
|
@ -135,6 +136,8 @@ public class MachineManager {
|
|||
* id of the workspace the created machine will belong to
|
||||
* @param environmentName
|
||||
* environment name the created machine will belongs to
|
||||
* @param outputConsumer
|
||||
* output consumer of machine
|
||||
* @return new machine
|
||||
* @throws NotFoundException
|
||||
* if machine type from recipe is unsupported
|
||||
|
|
@ -153,7 +156,8 @@ public class MachineManager {
|
|||
*/
|
||||
public MachineImpl createMachineSync(MachineConfig machineConfig,
|
||||
final String workspaceId,
|
||||
final String environmentName)
|
||||
final String environmentName,
|
||||
LineConsumer outputConsumer)
|
||||
throws NotFoundException,
|
||||
SnapshotException,
|
||||
ConflictException,
|
||||
|
|
@ -167,7 +171,8 @@ public class MachineManager {
|
|||
workspaceId,
|
||||
environmentName,
|
||||
this::createInstance,
|
||||
null);
|
||||
null,
|
||||
outputConsumer);
|
||||
LOG.info("Machine [ws = {}: env = {}: machine = {}] was successfully created, its id is '{}'",
|
||||
workspaceId,
|
||||
environmentName,
|
||||
|
|
@ -186,6 +191,8 @@ public class MachineManager {
|
|||
* workspace id
|
||||
* @param envName
|
||||
* name of environment
|
||||
* @param outputConsumer
|
||||
* output consumer of machine
|
||||
* @return machine instance
|
||||
* @throws NotFoundException
|
||||
* when snapshot doesn't exist
|
||||
|
|
@ -198,11 +205,15 @@ public class MachineManager {
|
|||
* @throws BadRequestException
|
||||
* when either machineConfig or workspace id, or environment name is not valid
|
||||
*/
|
||||
public MachineImpl recoverMachine(MachineConfig machineConfig, String workspaceId, String envName) throws NotFoundException,
|
||||
SnapshotException,
|
||||
MachineException,
|
||||
ConflictException,
|
||||
BadRequestException {
|
||||
public MachineImpl recoverMachine(MachineConfig machineConfig,
|
||||
String workspaceId,
|
||||
String envName,
|
||||
LineConsumer outputConsumer) throws NotFoundException,
|
||||
SnapshotException,
|
||||
MachineException,
|
||||
ConflictException,
|
||||
BadRequestException {
|
||||
|
||||
final SnapshotImpl snapshot = snapshotDao.getSnapshot(workspaceId, envName, machineConfig.getName());
|
||||
|
||||
LOG.info("Recovering machine [ws = {}: env = {}: machine = {}] from snapshot", workspaceId, envName, machineConfig.getName());
|
||||
|
|
@ -210,7 +221,8 @@ public class MachineManager {
|
|||
workspaceId,
|
||||
envName,
|
||||
this::createInstance,
|
||||
snapshot);
|
||||
snapshot,
|
||||
outputConsumer);
|
||||
LOG.info("Machine [ws = {}: env = {}: machine = {}] was successfully recovered, its id '{}'",
|
||||
workspaceId,
|
||||
envName,
|
||||
|
|
@ -229,6 +241,8 @@ public class MachineManager {
|
|||
* id of the workspace the created machine will belong to
|
||||
* @param environmentName
|
||||
* environment name the created machine will belongs to
|
||||
* @param outputConsumer
|
||||
* output consumer of machine
|
||||
* @return new machine
|
||||
* @throws NotFoundException
|
||||
* if machine type from recipe is unsupported
|
||||
|
|
@ -247,7 +261,8 @@ public class MachineManager {
|
|||
*/
|
||||
public MachineImpl createMachineAsync(MachineConfig machineConfig,
|
||||
final String workspaceId,
|
||||
final String environmentName)
|
||||
final String environmentName,
|
||||
LineConsumer outputConsumer)
|
||||
throws NotFoundException,
|
||||
SnapshotException,
|
||||
ConflictException,
|
||||
|
|
@ -269,14 +284,16 @@ public class MachineManager {
|
|||
// todo what should we do in that case?
|
||||
}
|
||||
})),
|
||||
null);
|
||||
null,
|
||||
outputConsumer);
|
||||
}
|
||||
|
||||
private MachineImpl createMachine(MachineConfigImpl machineConfig,
|
||||
String workspaceId,
|
||||
String environmentName,
|
||||
MachineInstanceCreator instanceCreator,
|
||||
SnapshotImpl snapshot)
|
||||
SnapshotImpl snapshot,
|
||||
LineConsumer outputConsumer)
|
||||
throws NotFoundException,
|
||||
SnapshotException,
|
||||
ConflictException,
|
||||
|
|
@ -329,38 +346,43 @@ public class MachineManager {
|
|||
null);
|
||||
|
||||
createMachineLogsDir(machineId);
|
||||
final LineConsumer machineLogger = getMachineLogger(machineId, getMachineChannels(machine.getConfig().getName(),
|
||||
machine.getWorkspaceId(),
|
||||
machine.getEnvName())
|
||||
.getOutput());
|
||||
final LineConsumer machineLogger = getMachineLogger(machineId, outputConsumer);
|
||||
|
||||
try {
|
||||
machineRegistry.addMachine(machine);
|
||||
try {
|
||||
machineRegistry.addMachine(machine);
|
||||
instanceCreator.createInstance(instanceProvider, machine, machineLogger);
|
||||
} catch (MachineException ex) {
|
||||
if (snapshot == null) {
|
||||
throw ex;
|
||||
}
|
||||
if (ex.getCause() instanceof SourceNotFoundException) {
|
||||
final LineConsumer logger = getMachineLogger(machineId,
|
||||
getMachineChannels(machine.getConfig().getName(),
|
||||
machine.getWorkspaceId(),
|
||||
machine.getEnvName()).getOutput());
|
||||
LOG.error("Image of snapshot for machine " + machineConfig.getName() + " not found. " +
|
||||
"Machine will be created from origin source");
|
||||
machine.getConfig().setSource(sourceCopy);
|
||||
try {
|
||||
machineRegistry.remove(machineId);
|
||||
} catch (NotFoundException ignored) {
|
||||
// machine is already removed, should never happen
|
||||
}
|
||||
machineRegistry.addMachine(machine);
|
||||
instanceCreator.createInstance(instanceProvider, machine, logger);
|
||||
instanceCreator.createInstance(instanceProvider, machine, outputConsumer);
|
||||
}
|
||||
}
|
||||
return machine;
|
||||
} catch (ConflictException e) {
|
||||
} catch (ApiException apiEx) {
|
||||
try {
|
||||
machineLogger.close();
|
||||
} catch (IOException ignored) {
|
||||
} catch (IOException ioEx) {
|
||||
LOG.error(ioEx.getLocalizedMessage(), ioEx);
|
||||
}
|
||||
throw new MachineException(e.getLocalizedMessage(), e);
|
||||
try {
|
||||
machineRegistry.remove(machineId);
|
||||
} catch (NotFoundException ignored) {
|
||||
// machine is already removed
|
||||
}
|
||||
|
||||
throw new MachineException(apiEx.getLocalizedMessage(), apiEx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -393,27 +415,28 @@ public class MachineManager {
|
|||
.withWorkspaceId(machine.getWorkspaceId())
|
||||
.withMachineName(machine.getConfig().getName()));
|
||||
|
||||
} catch (ServerException | InterruptedException e) {
|
||||
if (instance != null) {
|
||||
instance.destroy();
|
||||
}
|
||||
|
||||
} catch (ServerException | InterruptedException creationEx) {
|
||||
eventService.publish(DtoFactory.newDto(MachineStatusEvent.class)
|
||||
.withEventType(MachineStatusEvent.EventType.ERROR)
|
||||
.withMachineId(machine.getId())
|
||||
.withDev(machine.getConfig().isDev())
|
||||
.withWorkspaceId(machine.getWorkspaceId())
|
||||
.withMachineName(machine.getConfig().getName())
|
||||
.withError(e.getLocalizedMessage()));
|
||||
.withError(creationEx.getLocalizedMessage()));
|
||||
try {
|
||||
machineLogger.writeLine(String.format("[ERROR] %s", creationEx.getLocalizedMessage()));
|
||||
} catch (IOException ioEx) {
|
||||
LOG.error(ioEx.getLocalizedMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
machineRegistry.remove(machine.getId());
|
||||
machineLogger.writeLine(String.format("[ERROR] %s", e.getLocalizedMessage()));
|
||||
machineLogger.close();
|
||||
} catch (IOException | NotFoundException e1) {
|
||||
LOG.error(e1.getLocalizedMessage());
|
||||
if (instance != null) {
|
||||
instance.destroy();
|
||||
}
|
||||
} catch (MachineException destroyingEx) {
|
||||
LOG.error(destroyingEx.getLocalizedMessage(), destroyingEx);
|
||||
}
|
||||
throw new MachineException(e.getLocalizedMessage(), e);
|
||||
throw new MachineException(creationEx.getLocalizedMessage(), creationEx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -930,8 +953,8 @@ public class MachineManager {
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
LineConsumer getMachineLogger(String machineId, String outputChannel) throws MachineException {
|
||||
return getLogger(getMachineFileLogger(machineId), outputChannel);
|
||||
LineConsumer getMachineLogger(String machineId, LineConsumer outputConsumer) throws MachineException {
|
||||
return new CompositeLineConsumer(getMachineFileLogger(machineId), outputConsumer);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
@ -946,11 +969,6 @@ public class MachineManager {
|
|||
return fileLogger;
|
||||
}
|
||||
|
||||
static ChannelsImpl getMachineChannels(String machineName, String workspaceId, String envName) {
|
||||
return new ChannelsImpl(workspaceId + ':' + envName + ':' + machineName,
|
||||
"machine:status:" + workspaceId + ':' + machineName);
|
||||
}
|
||||
|
||||
// cleanup machine if event about instance failure comes
|
||||
private class MachineCleaner implements EventSubscriber<InstanceStateEvent> {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import org.eclipse.che.api.core.rest.ServiceContext;
|
|||
import org.eclipse.che.api.core.rest.shared.dto.Link;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.LinkParameter;
|
||||
import org.eclipse.che.api.machine.shared.Constants;
|
||||
import org.eclipse.che.api.machine.shared.dto.MachineConfigDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.MachineDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.MachineProcessDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.ServerDto;
|
||||
|
|
@ -30,11 +29,14 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
|
||||
import static org.eclipse.che.api.core.util.LinksHelper.createLink;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_STATUS_CHANNEL_TEMPLATE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.TERMINAL_REFERENCE;
|
||||
import static org.eclipse.che.dto.server.DtoFactory.cloneDto;
|
||||
import static org.eclipse.che.dto.server.DtoFactory.newDto;
|
||||
|
|
@ -118,23 +120,27 @@ public class MachineServiceLinksInjector {
|
|||
|
||||
injectTerminalLink(machine, serviceContext, links);
|
||||
|
||||
// add links to websocket channels
|
||||
final Link machineChannelLink = createLink("GET",
|
||||
serviceContext.getBaseUriBuilder()
|
||||
.path("ws")
|
||||
.path(machine.getWorkspaceId())
|
||||
.scheme("https".equals(getLogsUri.getScheme()) ? "wss" : "ws")
|
||||
.build()
|
||||
.toString(),
|
||||
null);
|
||||
// add workspace channel links
|
||||
final Link workspaceChannelLink = createLink("GET",
|
||||
serviceContext.getBaseUriBuilder()
|
||||
.path("ws")
|
||||
.path(machine.getWorkspaceId())
|
||||
.scheme("https".equals(getLogsUri.getScheme()) ? "wss" : "ws")
|
||||
.build()
|
||||
.toString(),
|
||||
null);
|
||||
final LinkParameter channelParameter = newDto(LinkParameter.class).withName("channel")
|
||||
.withRequired(true);
|
||||
|
||||
injectMachineChannelsLinks(machine.getConfig(),
|
||||
machine.getWorkspaceId(),
|
||||
machine.getEnvName(),
|
||||
machineChannelLink,
|
||||
channelParameter);
|
||||
links.add(cloneDto(workspaceChannelLink).withRel(LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL)
|
||||
.withParameters(singletonList(cloneDto(channelParameter)
|
||||
.withDefaultValue(format(ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE,
|
||||
machine.getWorkspaceId())))));
|
||||
|
||||
links.add(cloneDto(workspaceChannelLink).withRel(ENVIRONMENT_STATUS_CHANNEL_TEMPLATE)
|
||||
.withParameters(singletonList(cloneDto(channelParameter)
|
||||
.withDefaultValue(format(ENVIRONMENT_STATUS_CHANNEL_TEMPLATE,
|
||||
machine.getWorkspaceId())))));
|
||||
|
||||
return machine.withLinks(links);
|
||||
}
|
||||
|
|
@ -157,25 +163,6 @@ public class MachineServiceLinksInjector {
|
|||
}
|
||||
}
|
||||
|
||||
public void injectMachineChannelsLinks(MachineConfigDto machineConfig,
|
||||
String workspaceId,
|
||||
String envName,
|
||||
Link machineChannelLink,
|
||||
LinkParameter channelParameter) {
|
||||
final ChannelsImpl channels = MachineManager.getMachineChannels(machineConfig.getName(),
|
||||
workspaceId,
|
||||
envName);
|
||||
final Link getLogsLink = cloneDto(machineChannelLink)
|
||||
.withRel(org.eclipse.che.api.machine.shared.Constants.LINK_REL_GET_MACHINE_LOGS_CHANNEL)
|
||||
.withParameters(singletonList(cloneDto(channelParameter).withDefaultValue(channels.getOutput())));
|
||||
|
||||
final Link getStatusLink = cloneDto(machineChannelLink)
|
||||
.withRel(org.eclipse.che.api.machine.shared.Constants.LINK_REL_GET_MACHINE_STATUS_CHANNEL)
|
||||
.withParameters(singletonList(cloneDto(channelParameter).withDefaultValue(channels.getStatus())));
|
||||
|
||||
machineConfig.withLinks(asList(getLogsLink, getStatusLink));
|
||||
}
|
||||
|
||||
public MachineProcessDto injectLinks(MachineProcessDto process, String machineId, ServiceContext serviceContext) {
|
||||
final UriBuilder uriBuilder = serviceContext.getServiceUriBuilder();
|
||||
final List<Link> links = Lists.newArrayListWithExpectedSize(3);
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ import javax.annotation.PreDestroy;
|
|||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_STATUS_CHANNEL_TEMPLATE;
|
||||
|
||||
/**
|
||||
* Send machine state events using websocket channel to the clients
|
||||
*
|
||||
|
|
@ -44,7 +47,7 @@ public class MachineStateMessenger implements EventSubscriber<MachineStatusEvent
|
|||
public void onEvent(MachineStatusEvent event) {
|
||||
try {
|
||||
final ChannelBroadcastMessage bm = new ChannelBroadcastMessage();
|
||||
bm.setChannel("machine:status:" + event.getWorkspaceId() + ':' + event.getMachineName());
|
||||
bm.setChannel(format(ENVIRONMENT_STATUS_CHANNEL_TEMPLATE, event.getWorkspaceId()));
|
||||
bm.setBody(DtoFactory.getInstance().toJson(event));
|
||||
WSConnectionContext.sendMessage(bm);
|
||||
} catch (Exception e) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*******************************************************************************
|
||||
* 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.machine.server.model.impl;
|
||||
|
||||
import org.eclipse.che.api.core.model.machine.MachineLogMessage;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Alexander Garagatyi
|
||||
*/
|
||||
public class MachineLogMessageImpl implements MachineLogMessage {
|
||||
private String machineName;
|
||||
private String content;
|
||||
|
||||
public MachineLogMessageImpl() {}
|
||||
|
||||
public MachineLogMessageImpl(String machineName, String content) {
|
||||
this.machineName = machineName;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMachineName() {
|
||||
return machineName;
|
||||
}
|
||||
|
||||
public void setMachineName(String machine) {
|
||||
this.machineName = machine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof MachineLogMessageImpl)) return false;
|
||||
MachineLogMessageImpl that = (MachineLogMessageImpl)o;
|
||||
return Objects.equals(machineName, that.machineName) &&
|
||||
Objects.equals(content, that.content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(machineName, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MachineLogMessageImpl{machineName='" + machineName +
|
||||
"', content='" + content + "'}";
|
||||
}
|
||||
}
|
||||
|
|
@ -101,7 +101,7 @@ public class MachineManagerTest {
|
|||
@Mock
|
||||
private InstanceProcess instanceProcess;
|
||||
@Mock
|
||||
private LineConsumer processLogger;
|
||||
private LineConsumer logConsumer;
|
||||
@Mock
|
||||
private SnapshotDao snapshotDao;
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ public class MachineManagerTest {
|
|||
RecipeImpl recipe = new RecipeImpl().withScript("script").withType("Dockerfile");
|
||||
// doNothing().when(manager).createMachineLogsDir(anyString());
|
||||
doReturn(MACHINE_ID).when(manager).generateMachineId();
|
||||
doReturn(processLogger).when(manager).getProcessLogger(MACHINE_ID, 111, "outputChannel");
|
||||
doReturn(logConsumer).when(manager).getProcessLogger(MACHINE_ID, 111, "outputChannel");
|
||||
when(machineInstanceProviders.getProvider(anyString())).thenReturn(instanceProvider);
|
||||
HashSet<String> recipeTypes = new HashSet<>();
|
||||
recipeTypes.add("test type 1");
|
||||
|
|
@ -168,7 +168,7 @@ public class MachineManagerTest {
|
|||
String workspaceId = "wsId";
|
||||
String environmentName = "env1";
|
||||
|
||||
manager.createMachineSync(machineConfig, workspaceId, environmentName);
|
||||
manager.createMachineSync(machineConfig, workspaceId, environmentName, logConsumer);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -186,7 +186,7 @@ public class MachineManagerTest {
|
|||
MachineStatus.CREATING,
|
||||
null);
|
||||
|
||||
manager.createMachineSync(machineConfig, WS_ID, ENVIRONMENT_NAME);
|
||||
manager.createMachineSync(machineConfig, WS_ID, ENVIRONMENT_NAME, logConsumer);
|
||||
|
||||
verify(machineRegistry).addMachine(eq(expectedMachine));
|
||||
}
|
||||
|
|
@ -198,7 +198,7 @@ public class MachineManagerTest {
|
|||
.setDev(true)
|
||||
.build();
|
||||
|
||||
manager.createMachineSync(machineConfig, WS_ID, ENVIRONMENT_NAME);
|
||||
manager.createMachineSync(machineConfig, WS_ID, ENVIRONMENT_NAME, logConsumer);
|
||||
|
||||
verify(wsAgentLauncher).startWsAgent(WS_ID);
|
||||
}
|
||||
|
|
@ -207,7 +207,7 @@ public class MachineManagerTest {
|
|||
public void shouldNotCallWsAgentLauncherAfterNonDevMachineStart() throws Exception {
|
||||
final MachineConfigImpl machineConfig = createMachineConfig();
|
||||
|
||||
manager.createMachineSync(machineConfig, WS_ID, ENVIRONMENT_NAME);
|
||||
manager.createMachineSync(machineConfig, WS_ID, ENVIRONMENT_NAME, logConsumer);
|
||||
|
||||
verify(wsAgentLauncher, never()).startWsAgent(WS_ID);
|
||||
}
|
||||
|
|
@ -233,7 +233,7 @@ public class MachineManagerTest {
|
|||
waitForExecutorIsCompletedTask();
|
||||
|
||||
//then
|
||||
verify(processLogger).close();
|
||||
verify(logConsumer).close();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -246,7 +246,7 @@ public class MachineManagerTest {
|
|||
waitForExecutorIsCompletedTask();
|
||||
|
||||
//then
|
||||
verify(processLogger).close();
|
||||
verify(logConsumer).close();
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = MachineException.class)
|
||||
|
|
@ -255,14 +255,14 @@ public class MachineManagerTest {
|
|||
MachineConfig machineConfig = mock(MachineConfig.class);
|
||||
MachineSource machineSource = mock(MachineSource.class);
|
||||
LineConsumer machineLogger = mock(LineConsumer.class);
|
||||
doReturn(machineLogger).when(manager).getMachineLogger(MACHINE_ID, "outputChannel");
|
||||
doReturn(machineLogger).when(manager).getMachineLogger(eq(MACHINE_ID), any(LineConsumer.class));
|
||||
when(machineConfig.getSource()).thenReturn(machineSource);
|
||||
when(machineConfig.getName()).thenReturn("Name");
|
||||
when(machineSource.getType()).thenReturn("dockerfile");
|
||||
doThrow(ConflictException.class).when(machineRegistry).addMachine(any());
|
||||
|
||||
//when
|
||||
manager.createMachineSync(machineConfig, "workspaceId", "environmentName");
|
||||
manager.createMachineSync(machineConfig, "workspaceId", "environmentName", logConsumer);
|
||||
|
||||
//then
|
||||
verify(machineLogger).close();
|
||||
|
|
@ -285,7 +285,7 @@ public class MachineManagerTest {
|
|||
when(instanceProvider.createInstance(eq(machine), any(LineConsumer.class))).thenThrow(new SourceNotFoundException(""));
|
||||
when(machineRegistry.getMachine(MACHINE_ID)).thenReturn(machine);
|
||||
|
||||
final MachineImpl result = manager.recoverMachine(config, WS_ID, ENVIRONMENT_NAME);
|
||||
final MachineImpl result = manager.recoverMachine(config, WS_ID, ENVIRONMENT_NAME, logConsumer);
|
||||
|
||||
machine.getConfig().setSource(config.getSource());
|
||||
assertEquals(result, machine);
|
||||
|
|
@ -299,7 +299,7 @@ public class MachineManagerTest {
|
|||
when(instanceProvider.createInstance(any(MachineImpl.class),
|
||||
any(LineConsumer.class))).thenThrow(new MachineException(""));
|
||||
|
||||
manager.recoverMachine(config, WS_ID, ENVIRONMENT_NAME);
|
||||
manager.recoverMachine(config, WS_ID, ENVIRONMENT_NAME, logConsumer);
|
||||
}
|
||||
|
||||
private void waitForExecutorIsCompletedTask() throws Exception {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ import java.util.Set;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_STATUS_CHANNEL_TEMPLATE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_DESTROY_MACHINE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_EXECUTE_COMMAND;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_GET_MACHINES;
|
||||
|
|
@ -103,7 +105,9 @@ public class MachineServiceLinksInjectorTest {
|
|||
Pair.of("GET", LINK_REL_GET_SNAPSHOTS),
|
||||
Pair.of("GET", LINK_REL_GET_PROCESSES),
|
||||
Pair.of("POST", LINK_REL_SAVE_SNAPSHOT),
|
||||
Pair.of("GET", LINK_REL_GET_MACHINE_LOGS)));
|
||||
Pair.of("GET", LINK_REL_GET_MACHINE_LOGS),
|
||||
Pair.of("GET", LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL),
|
||||
Pair.of("GET", ENVIRONMENT_STATUS_CHANNEL_TEMPLATE)));
|
||||
|
||||
assertEquals(links, expectedLinks, "Difference " + Sets.symmetricDifference(links, expectedLinks) + "\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,10 +15,12 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|||
import com.google.inject.Inject;
|
||||
|
||||
import org.eclipse.che.api.core.ApiException;
|
||||
import org.eclipse.che.api.core.BadRequestException;
|
||||
import org.eclipse.che.api.core.ConflictException;
|
||||
import org.eclipse.che.api.core.ForbiddenException;
|
||||
import org.eclipse.che.api.core.NotFoundException;
|
||||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.machine.MachineConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.Workspace;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
|
||||
|
|
@ -424,6 +426,42 @@ public class WorkspaceManager {
|
|||
return normalizeState(workspace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts machine in running workspace
|
||||
*
|
||||
* @param machineConfig configuration of machine to start
|
||||
* @param workspaceId id of workspace in which machine should be started
|
||||
* @return starting machine instance
|
||||
* @throws NotFoundException
|
||||
* if machine type from recipe is unsupported
|
||||
* @throws NotFoundException
|
||||
* if no instance provider implementation found for provided machine type
|
||||
* @throws ConflictException
|
||||
* if machine with given name already exists
|
||||
* @throws ConflictException
|
||||
* if workspace is not in RUNNING state
|
||||
* @throws BadRequestException
|
||||
* if machine name is invalid
|
||||
* @throws ServerException
|
||||
* if any other exception occurs during starting
|
||||
*/
|
||||
public MachineImpl startMachine(MachineConfig machineConfig, String workspaceId)
|
||||
throws ServerException,
|
||||
ConflictException,
|
||||
BadRequestException,
|
||||
NotFoundException {
|
||||
|
||||
final WorkspaceImpl workspace = getWorkspace(workspaceId);
|
||||
if (RUNNING != workspace.getStatus()) {
|
||||
throw new ConflictException(format("Workspace '%s' is not running, new machine can't be started", workspaceId));
|
||||
}
|
||||
|
||||
return machineManager.createMachineAsync(machineConfig,
|
||||
workspaceId,
|
||||
workspace.getRuntime().getActiveEnv(),
|
||||
runtimes.getMachineLogger(workspaceId, machineConfig.getName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously stops the workspace.
|
||||
*
|
||||
|
|
@ -495,6 +533,19 @@ public class WorkspaceManager {
|
|||
return machineManager.getSnapshots(workspace.getNamespace(), workspaceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all snapshots of workspace machines
|
||||
*
|
||||
* @param workspaceId workspace id to remove machine snapshots
|
||||
* @throws NotFoundException
|
||||
* when workspace with given id doesn't exists
|
||||
* @throws ServerException
|
||||
* when any other error occurs
|
||||
*/
|
||||
public void removeSnapshots(String workspaceId) throws NotFoundException, ServerException {
|
||||
machineManager.removeSnapshots(getWorkspace(workspaceId).getNamespace(), workspaceId);
|
||||
}
|
||||
|
||||
/** Asynchronously starts given workspace. */
|
||||
@VisibleForTesting
|
||||
WorkspaceImpl performAsyncStart(WorkspaceImpl workspace,
|
||||
|
|
|
|||
|
|
@ -19,15 +19,20 @@ import org.eclipse.che.api.core.NotFoundException;
|
|||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.model.machine.Machine;
|
||||
import org.eclipse.che.api.core.model.machine.MachineConfig;
|
||||
import org.eclipse.che.api.core.model.machine.MachineLogMessage;
|
||||
import org.eclipse.che.api.core.model.machine.MachineStatus;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceRuntime;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.notification.EventSubscriber;
|
||||
import org.eclipse.che.api.core.util.AbstractLineConsumer;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.core.util.WebsocketMessageConsumer;
|
||||
import org.eclipse.che.api.machine.server.MachineManager;
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.machine.server.model.impl.MachineConfigImpl;
|
||||
import org.eclipse.che.api.machine.server.model.impl.MachineImpl;
|
||||
import org.eclipse.che.api.machine.server.model.impl.MachineLogMessageImpl;
|
||||
import org.eclipse.che.api.machine.shared.dto.event.MachineStatusEvent;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
|
||||
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
|
||||
|
|
@ -41,6 +46,7 @@ import javax.annotation.PostConstruct;
|
|||
import javax.annotation.PreDestroy;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
|
@ -52,6 +58,7 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||
import java.util.function.Predicate;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE;
|
||||
import static org.eclipse.che.dto.server.DtoFactory.newDto;
|
||||
|
||||
/**
|
||||
|
|
@ -164,7 +171,7 @@ public class WorkspaceRuntimes {
|
|||
* @throws ServerException
|
||||
* when component {@link #isPreDestroyInvoked is stopped} or any
|
||||
* other error occurs during environment start
|
||||
* @see MachineManager#createMachineSync(MachineConfig, String, String)
|
||||
* @see MachineManager#createMachineSync(MachineConfig, String, String, org.eclipse.che.api.core.util.LineConsumer)
|
||||
* @see WorkspaceStatus#STARTING
|
||||
* @see WorkspaceStatus#RUNNING
|
||||
*/
|
||||
|
|
@ -574,12 +581,15 @@ public class WorkspaceRuntimes {
|
|||
boolean recover) throws ServerException,
|
||||
NotFoundException,
|
||||
ConflictException {
|
||||
|
||||
LineConsumer machineLogger = getMachineLogger(workspaceId, config.getName());
|
||||
|
||||
MachineImpl machine;
|
||||
try {
|
||||
if (recover) {
|
||||
machine = machineManager.recoverMachine(config, workspaceId, envName);
|
||||
machine = machineManager.recoverMachine(config, workspaceId, envName, machineLogger);
|
||||
} else {
|
||||
machine = machineManager.createMachineSync(config, workspaceId, envName);
|
||||
machine = machineManager.createMachineSync(config, workspaceId, envName, machineLogger);
|
||||
}
|
||||
} catch (ConflictException x) {
|
||||
// The conflict is because of the already running machine
|
||||
|
|
@ -614,6 +624,17 @@ public class WorkspaceRuntimes {
|
|||
return machine;
|
||||
}
|
||||
|
||||
protected LineConsumer getMachineLogger(String workspaceId, String machineName) throws ServerException {
|
||||
WebsocketMessageConsumer<MachineLogMessage> envMessageConsumer =
|
||||
new WebsocketMessageConsumer<>(format(ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE, workspaceId));
|
||||
return new AbstractLineConsumer() {
|
||||
@Override
|
||||
public void writeLine(String line) throws IOException {
|
||||
envMessageConsumer.consume(new MachineLogMessageImpl(machineName, line));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the {@link WorkspaceRuntime} instance.
|
||||
* Knows the state of the started workspace runtime,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import org.eclipse.che.api.core.NotFoundException;
|
|||
import org.eclipse.che.api.core.ServerException;
|
||||
import org.eclipse.che.api.core.rest.Service;
|
||||
import org.eclipse.che.api.core.rest.annotations.GenerateLink;
|
||||
import org.eclipse.che.api.machine.server.MachineManager;
|
||||
import org.eclipse.che.api.machine.server.model.impl.CommandImpl;
|
||||
import org.eclipse.che.api.machine.server.model.impl.MachineImpl;
|
||||
import org.eclipse.che.api.machine.shared.dto.CommandDto;
|
||||
|
|
@ -81,7 +80,6 @@ public class WorkspaceService extends Service {
|
|||
|
||||
private final WorkspaceManager workspaceManager;
|
||||
private final WorkspaceValidator validator;
|
||||
private final MachineManager machineManager;
|
||||
private final WorkspaceServiceLinksInjector linksInjector;
|
||||
|
||||
@Context
|
||||
|
|
@ -89,11 +87,9 @@ public class WorkspaceService extends Service {
|
|||
|
||||
@Inject
|
||||
public WorkspaceService(WorkspaceManager workspaceManager,
|
||||
MachineManager machineManager,
|
||||
WorkspaceValidator validator,
|
||||
WorkspaceServiceLinksInjector workspaceServiceLinksInjector) {
|
||||
this.workspaceManager = workspaceManager;
|
||||
this.machineManager = machineManager;
|
||||
this.validator = validator;
|
||||
this.linksInjector = workspaceServiceLinksInjector;
|
||||
}
|
||||
|
|
@ -240,7 +236,7 @@ public class WorkspaceService extends Service {
|
|||
ConflictException,
|
||||
ForbiddenException {
|
||||
if (!workspaceManager.getSnapshot(id).isEmpty()) {
|
||||
machineManager.removeSnapshots(workspaceManager.getWorkspace(id).getNamespace(), id);
|
||||
workspaceManager.removeSnapshots(id);
|
||||
}
|
||||
workspaceManager.removeWorkspace(id);
|
||||
}
|
||||
|
|
@ -646,7 +642,8 @@ public class WorkspaceService extends Service {
|
|||
@ApiResponse(code = 400, message = "Missed required parameters, parameters are not valid"),
|
||||
@ApiResponse(code = 403, message = "The user does not have access to create the new machine"),
|
||||
@ApiResponse(code = 409, message = "Conflict error occurred during the machine creation" +
|
||||
"(e.g. The machine with such name already exists)"),
|
||||
"(e.g. The machine with such name already exists)." +
|
||||
"Workspace is not in RUNNING state"),
|
||||
@ApiResponse(code = 500, message = "Internal server error occurred")})
|
||||
public Response createMachine(@ApiParam("The workspace id")
|
||||
@PathParam("id")
|
||||
|
|
@ -665,14 +662,7 @@ public class WorkspaceService extends Service {
|
|||
requiredOnlyOneNotNull(machineConfig.getSource().getLocation(), machineConfig.getSource().getContent(),
|
||||
"Machine source should provide either location or content");
|
||||
|
||||
final WorkspaceImpl workspace = workspaceManager.getWorkspace(workspaceId);
|
||||
if (workspace.getRuntime() == null) {
|
||||
throw new NotFoundException(format("Workspace '%s' is not running, new machine can't be started", workspaceId));
|
||||
}
|
||||
|
||||
final MachineImpl machine = machineManager.createMachineAsync(machineConfig,
|
||||
workspaceId,
|
||||
workspace.getRuntime().getActiveEnv());
|
||||
final MachineImpl machine = workspaceManager.startMachine(machineConfig, workspaceId);
|
||||
|
||||
return Response.status(201)
|
||||
.entity(linksInjector.injectMachineLinks(org.eclipse.che.api.machine.server.DtoConverter.asDto(machine),
|
||||
|
|
|
|||
|
|
@ -14,11 +14,9 @@ import org.eclipse.che.api.core.rest.ServiceContext;
|
|||
import org.eclipse.che.api.core.rest.shared.dto.Link;
|
||||
import org.eclipse.che.api.core.rest.shared.dto.LinkParameter;
|
||||
import org.eclipse.che.api.machine.server.MachineServiceLinksInjector;
|
||||
import org.eclipse.che.api.machine.shared.dto.MachineConfigDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.MachineDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.ServerDto;
|
||||
import org.eclipse.che.api.machine.shared.dto.SnapshotDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
|
||||
import org.eclipse.che.api.workspace.shared.dto.WorkspaceRuntimeDto;
|
||||
|
||||
|
|
@ -31,12 +29,17 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.String.format;
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
|
||||
import static javax.ws.rs.core.MediaType.TEXT_HTML;
|
||||
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING;
|
||||
import static org.eclipse.che.api.core.util.LinksHelper.createLink;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_STATUS_CHANNEL_TEMPLATE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_ENVIRONMENT_STATUS_CHANNEL;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.TERMINAL_REFERENCE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.WSAGENT_REFERENCE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.WSAGENT_WEBSOCKET_REFERENCE;
|
||||
|
|
@ -116,7 +119,7 @@ public class WorkspaceServiceLinksInjector {
|
|||
.build();
|
||||
links.add(createLink("GET", ideUri.toString(), TEXT_HTML, LINK_REL_IDE_URL));
|
||||
|
||||
// add workspace channel link
|
||||
// add workspace channel links
|
||||
final Link workspaceChannelLink = createLink("GET",
|
||||
serviceContext.getBaseUriBuilder()
|
||||
.path("ws")
|
||||
|
|
@ -132,14 +135,16 @@ public class WorkspaceServiceLinksInjector {
|
|||
.withParameters(singletonList(
|
||||
cloneDto(channelParameter).withDefaultValue("workspace:" + workspace.getId()))));
|
||||
|
||||
// add machine channels links to machines configs
|
||||
workspace.getConfig()
|
||||
.getEnvironments()
|
||||
.stream()
|
||||
.forEach(environmentDto -> injectMachineChannelsLinks(environmentDto,
|
||||
workspace.getId(),
|
||||
workspaceChannelLink,
|
||||
channelParameter));
|
||||
links.add(cloneDto(workspaceChannelLink).withRel(LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL)
|
||||
.withParameters(singletonList(cloneDto(channelParameter)
|
||||
.withDefaultValue(format(ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE,
|
||||
workspace.getId())))));
|
||||
|
||||
links.add(cloneDto(workspaceChannelLink).withRel(LINK_REL_ENVIRONMENT_STATUS_CHANNEL)
|
||||
.withParameters(singletonList(cloneDto(channelParameter)
|
||||
.withDefaultValue(format(ENVIRONMENT_STATUS_CHANNEL_TEMPLATE,
|
||||
workspace.getId())))));
|
||||
|
||||
// add links for running workspace
|
||||
injectRuntimeLinks(workspace, ideUri, uriBuilder);
|
||||
return workspace.withLinks(links);
|
||||
|
|
@ -233,17 +238,4 @@ public class WorkspaceServiceLinksInjector {
|
|||
public MachineDto injectMachineLinks(MachineDto machine, ServiceContext serviceContext) {
|
||||
return machineLinksInjector.injectLinks(machine, serviceContext);
|
||||
}
|
||||
|
||||
private void injectMachineChannelsLinks(EnvironmentDto environmentDto,
|
||||
String workspaceId,
|
||||
Link machineChannelLink,
|
||||
LinkParameter channelParameter) {
|
||||
for (MachineConfigDto machineConfigDto : environmentDto.getMachineConfigs()) {
|
||||
machineLinksInjector.injectMachineChannelsLinks(machineConfigDto,
|
||||
workspaceId,
|
||||
environmentDto.getName(),
|
||||
machineChannelLink,
|
||||
channelParameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import org.eclipse.che.api.core.NotFoundException;
|
|||
import org.eclipse.che.api.core.model.workspace.WorkspaceConfig;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.machine.server.MachineManager;
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.machine.server.model.impl.MachineConfigImpl;
|
||||
|
|
@ -59,6 +60,7 @@ import static org.mockito.Matchers.any;
|
|||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
|
@ -637,6 +639,57 @@ public class WorkspaceManagerTest {
|
|||
verify(runtimes, timeout(2000)).start(workspace, workspace.getConfig().getDefaultEnv(), true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToRemoveMachinesSnapshots() throws Exception {
|
||||
// given
|
||||
String testWsId = "testWsId";
|
||||
String testNamespace = "testNamespace";
|
||||
WorkspaceImpl workspaceMock = mock(WorkspaceImpl.class);
|
||||
doReturn(workspaceMock).when(workspaceManager).getWorkspace(testWsId);
|
||||
when(workspaceMock.getNamespace()).thenReturn(testNamespace);
|
||||
|
||||
// when
|
||||
workspaceManager.removeSnapshots(testWsId);
|
||||
|
||||
// then
|
||||
verify(machineManager).removeSnapshots(testNamespace, testWsId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldBeAbleToStartMachineInRunningWs() throws Exception {
|
||||
// given
|
||||
String testWsId = "testWsId";
|
||||
String testActiveEnv = "testActiveEnv";
|
||||
WorkspaceImpl workspaceMock = mock(WorkspaceImpl.class);
|
||||
doReturn(workspaceMock).when(workspaceManager).getWorkspace(testWsId);
|
||||
WorkspaceRuntimeImpl wsRuntimeMock = mock(WorkspaceRuntimeImpl.class);
|
||||
when(workspaceMock.getStatus()).thenReturn(RUNNING);
|
||||
when(workspaceMock.getRuntime()).thenReturn(wsRuntimeMock);
|
||||
when(wsRuntimeMock.getActiveEnv()).thenReturn(testActiveEnv);
|
||||
LineConsumer lineConsumerMock = mock(LineConsumer.class);
|
||||
MachineConfigImpl machineConfig = createConfig().getEnvironments().get(0).getMachineConfigs().get(0);
|
||||
when(runtimes.getMachineLogger(testWsId, machineConfig.getName())).thenReturn(lineConsumerMock);
|
||||
|
||||
// when
|
||||
workspaceManager.startMachine(machineConfig, testWsId);
|
||||
|
||||
// then
|
||||
verify(machineManager).createMachineAsync(eq(machineConfig), eq(testWsId), eq(testActiveEnv), eq(lineConsumerMock));
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = ConflictException.class, expectedExceptionsMessageRegExp = "Workspace .* is not running, new machine can't be started")
|
||||
public void shouldThrowExceptionOnStartMachineInNonRunningWs() throws Exception {
|
||||
// given
|
||||
String testWsId = "testWsId";
|
||||
WorkspaceImpl workspaceMock = mock(WorkspaceImpl.class);
|
||||
doReturn(workspaceMock).when(workspaceManager).getWorkspace(testWsId);
|
||||
when(workspaceMock.getStatus()).thenReturn(STARTING);
|
||||
MachineConfigImpl machineConfig = createConfig().getEnvironments().get(0).getMachineConfigs().get(0);
|
||||
|
||||
// when
|
||||
workspaceManager.startMachine(machineConfig, testWsId);
|
||||
}
|
||||
|
||||
private RuntimeDescriptor createDescriptor(WorkspaceImpl workspace, WorkspaceStatus status) {
|
||||
final WorkspaceRuntimeImpl runtime = new WorkspaceRuntimeImpl(workspace.getConfig().getDefaultEnv());
|
||||
final String env = workspace.getConfig().getDefaultEnv();
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import org.eclipse.che.api.core.model.machine.MachineConfig;
|
|||
import org.eclipse.che.api.core.model.machine.MachineStatus;
|
||||
import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
|
||||
import org.eclipse.che.api.core.notification.EventService;
|
||||
import org.eclipse.che.api.core.util.LineConsumer;
|
||||
import org.eclipse.che.api.machine.server.MachineManager;
|
||||
import org.eclipse.che.api.machine.server.exception.MachineException;
|
||||
import org.eclipse.che.api.machine.server.model.impl.LimitsImpl;
|
||||
|
|
@ -53,6 +54,7 @@ import static org.mockito.Matchers.any;
|
|||
import static org.mockito.Matchers.anyBoolean;
|
||||
import static org.mockito.Matchers.anyObject;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doNothing;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
|
|
@ -90,7 +92,7 @@ public class WorkspaceRuntimesTest {
|
|||
|
||||
@BeforeMethod
|
||||
public void setUp() throws Exception {
|
||||
when(machineManager.createMachineSync(any(), any(), any()))
|
||||
when(machineManager.createMachineSync(any(), any(), any(), any(LineConsumer.class)))
|
||||
.thenAnswer(invocation -> createMachine((MachineConfig)invocation.getArguments()[0]));
|
||||
runtimes = new WorkspaceRuntimes(machineManager, eventService);
|
||||
}
|
||||
|
|
@ -117,7 +119,7 @@ public class WorkspaceRuntimesTest {
|
|||
final WorkspaceImpl workspace = createWorkspace();
|
||||
|
||||
// check if workspace in starting status before dev machine is started
|
||||
when(machineManagerMock.createMachineSync(anyObject(), anyString(), anyString()))
|
||||
when(machineManagerMock.createMachineSync(anyObject(), anyString(), anyString(), any(LineConsumer.class)))
|
||||
.thenAnswer(invocationOnMock -> {
|
||||
final RuntimeDescriptor descriptor = runtimes.get(workspace.getId());
|
||||
final MachineConfig cfg = (MachineConfig)invocationOnMock.getArguments()[0];
|
||||
|
|
@ -129,7 +131,7 @@ public class WorkspaceRuntimesTest {
|
|||
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv(), false);
|
||||
|
||||
verify(machineManagerMock, times(2)).createMachineSync(anyObject(), anyString(), anyString());
|
||||
verify(machineManagerMock, times(2)).createMachineSync(anyObject(), anyString(), anyString(), any(LineConsumer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -137,7 +139,7 @@ public class WorkspaceRuntimesTest {
|
|||
final MachineManager machineManagerMock = mock(MachineManager.class);
|
||||
final WorkspaceRuntimes runtimes = new WorkspaceRuntimes(machineManagerMock, eventService);
|
||||
final WorkspaceImpl workspaceMock = createWorkspace();
|
||||
when(machineManagerMock.createMachineSync(any(), any(), any()))
|
||||
when(machineManagerMock.createMachineSync(any(), any(), any(), any(LineConsumer.class)))
|
||||
.thenThrow(new MachineException("Creation error"));
|
||||
|
||||
try {
|
||||
|
|
@ -175,7 +177,7 @@ public class WorkspaceRuntimesTest {
|
|||
final WorkspaceRuntimes registry = new WorkspaceRuntimes(machineManagerMock, eventService);
|
||||
final WorkspaceImpl workspace = createWorkspace();
|
||||
|
||||
when(machineManagerMock.createMachineSync(any(), any(), any())).thenAnswer(invocationOnMock -> {
|
||||
when(machineManagerMock.createMachineSync(any(), any(), any(), any(LineConsumer.class))).thenAnswer(invocationOnMock -> {
|
||||
registry.stop(workspace.getId());
|
||||
return createMachine((MachineConfig)invocationOnMock.getArguments()[0]);
|
||||
});
|
||||
|
|
@ -193,7 +195,7 @@ public class WorkspaceRuntimesTest {
|
|||
runtimes.stop(workspace.getId());
|
||||
}
|
||||
return createMachine((MachineConfig)invocation.getArguments()[0]);
|
||||
}).when(machineManager).createMachineSync(any(), anyString(), anyString());
|
||||
}).when(machineManager).createMachineSync(any(), anyString(), anyString(), any(LineConsumer.class));
|
||||
|
||||
try {
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
|
|
@ -224,7 +226,7 @@ public class WorkspaceRuntimesTest {
|
|||
throw new MachineException("Failed to start");
|
||||
}
|
||||
return createMachine((MachineConfig)invocation.getArguments()[0]);
|
||||
}).when(machineManager).createMachineSync(any(), anyString(), anyString());
|
||||
}).when(machineManager).createMachineSync(any(), anyString(), anyString(), any(LineConsumer.class));
|
||||
|
||||
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
|
|
@ -232,7 +234,7 @@ public class WorkspaceRuntimesTest {
|
|||
final RuntimeDescriptor descriptor = runtimes.get(workspace.getId());
|
||||
assertEquals(descriptor.getRuntime().getMachines().size(), 1);
|
||||
assertEquals(descriptor.getRuntimeStatus(), RUNNING);
|
||||
verify(machineManager, times(2)).createMachineSync(any(), any(), any());
|
||||
verify(machineManager, times(2)).createMachineSync(any(), any(), any(), any(LineConsumer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -245,7 +247,7 @@ public class WorkspaceRuntimesTest {
|
|||
runtimes.cleanup();
|
||||
}
|
||||
return createMachine((MachineConfig)invocation.getArguments()[0]);
|
||||
}).when(machineManager).createMachineSync(any(), anyString(), anyString());
|
||||
}).when(machineManager).createMachineSync(any(), anyString(), anyString(), any(LineConsumer.class));
|
||||
|
||||
try {
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
|
|
@ -323,7 +325,7 @@ public class WorkspaceRuntimesTest {
|
|||
doAnswer(invocation -> {
|
||||
verify(runtimes).publishEvent(EventType.STARTING, workspace.getId(), null);
|
||||
return null;
|
||||
}).when(machineManager).createMachineSync(any(), any(), any());
|
||||
}).when(machineManager).createMachineSync(any(), any(), any(), any(LineConsumer.class));
|
||||
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
}
|
||||
|
|
@ -340,7 +342,7 @@ public class WorkspaceRuntimesTest {
|
|||
verify(runtimes).publishEvent(EventType.RUNNING, workspace.getId(), null);
|
||||
}
|
||||
return createMachine(cfg);
|
||||
}).when(machineManager).createMachineSync(any(), any(), any());
|
||||
}).when(machineManager).createMachineSync(any(), any(), any(), any(LineConsumer.class));
|
||||
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
}
|
||||
|
|
@ -358,7 +360,7 @@ public class WorkspaceRuntimesTest {
|
|||
throw new MachineException("Start error");
|
||||
}
|
||||
return createMachine(cfg);
|
||||
}).when(machineManager).createMachineSync(any(), any(), any());
|
||||
}).when(machineManager).createMachineSync(any(), any(), any(), any(LineConsumer.class));
|
||||
|
||||
try {
|
||||
runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
|
|
@ -652,9 +654,10 @@ public class WorkspaceRuntimesTest {
|
|||
// force machine manager to throw conflict exception
|
||||
final RuntimeDescriptor descriptorMock = mock(RuntimeDescriptor.class);
|
||||
when(descriptorMock.getRuntimeStatus()).thenReturn(WorkspaceStatus.RUNNING);
|
||||
doThrow(new ConflictException("already exists")).when(machineManager).createMachineSync(machine.getConfig(),
|
||||
machine.getWorkspaceId(),
|
||||
workspace.getConfig().getDefaultEnv());
|
||||
doThrow(new ConflictException("already exists")).when(machineManager).createMachineSync(eq(machine.getConfig()),
|
||||
eq(machine.getWorkspaceId()),
|
||||
eq(workspace.getConfig().getDefaultEnv()),
|
||||
any(LineConsumer.class));
|
||||
|
||||
final RuntimeDescriptor descriptor = runtimes.start(workspace, workspace.getConfig().getDefaultEnv());
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@ import static java.util.stream.Collectors.toList;
|
|||
import static java.util.stream.Collectors.toSet;
|
||||
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING;
|
||||
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STARTING;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.LINK_REL_ENVIRONMENT_STATUS_CHANNEL;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.WSAGENT_REFERENCE;
|
||||
import static org.eclipse.che.api.machine.shared.Constants.WSAGENT_WEBSOCKET_REFERENCE;
|
||||
import static org.eclipse.che.api.workspace.shared.Constants.GET_ALL_USER_WORKSPACES;
|
||||
|
|
@ -127,7 +129,6 @@ public class WorkspaceServiceTest {
|
|||
@BeforeMethod
|
||||
public void setup() {
|
||||
service = new WorkspaceService(wsManager,
|
||||
machineManager,
|
||||
validator,
|
||||
new WorkspaceServiceLinksInjector(new MachineServiceLinksInjector()));
|
||||
}
|
||||
|
|
@ -295,7 +296,7 @@ public class WorkspaceServiceTest {
|
|||
.delete(SECURE_PATH + "/workspace/" + workspace.getId());
|
||||
|
||||
assertEquals(response.getStatusCode(), 204);
|
||||
verify(machineManager).removeSnapshots(NAMESPACE, workspace.getId());
|
||||
verify(wsManager).removeSnapshots(workspace.getId());
|
||||
verify(wsManager).removeWorkspace(workspace.getId());
|
||||
}
|
||||
|
||||
|
|
@ -681,7 +682,9 @@ public class WorkspaceServiceTest {
|
|||
LINK_REL_GET_SNAPSHOT,
|
||||
LINK_REL_GET_WORKSPACE_EVENTS_CHANNEL,
|
||||
LINK_REL_IDE_URL,
|
||||
LINK_REL_SELF));
|
||||
LINK_REL_SELF,
|
||||
LINK_REL_ENVIRONMENT_OUTPUT_CHANNEL,
|
||||
LINK_REL_ENVIRONMENT_STATUS_CHANNEL));
|
||||
assertTrue(actualRels.equals(expectedRels), format("Links difference: '%s'. \n" +
|
||||
"Returned links: '%s', \n" +
|
||||
"Expected links: '%s'.",
|
||||
|
|
|
|||
Loading…
Reference in New Issue