diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceStatus.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceStatus.java
index 8d71e81c61..2c2b4adcb6 100644
--- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceStatus.java
+++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/WorkspaceStatus.java
@@ -46,6 +46,18 @@ public enum WorkspaceStatus {
*/
RUNNING,
+ /**
+ * Workspace is in SNAPSHOTTING status if and only if the workspace
+ * is currently creating snapshots of it's machines.
+ *
+ *
Workspace is in SNAPSHOTTING status after it was {@link #RUNNING}.
+ * The status map:
+ *
+ * RUNNING -> SNAPSHOTTING -> RUNNING (normal behaviour/error while snapshotting)
+ *
+ */
+ SNAPSHOTTING,
+
/**
* Workspace considered as stopping if and only if its active environment is shutting down.
*
diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java
index 0cd1f7407c..b38644e52a 100644
--- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java
+++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/jpa/JpaSnapshotDao.java
@@ -23,6 +23,7 @@ import javax.inject.Provider;
import javax.inject.Singleton;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
+import java.util.Collection;
import java.util.List;
import static java.lang.String.format;
@@ -117,6 +118,20 @@ public class JpaSnapshotDao implements SnapshotDao {
}
}
+ @Override
+ public List replaceSnapshots(String workspaceId,
+ String envName,
+ Collection extends SnapshotImpl> newSnapshots) throws SnapshotException {
+ requireNonNull(workspaceId, "Required non-null workspace id");
+ requireNonNull(envName, "Required non-null environment name");
+ requireNonNull(newSnapshots, "Required non-null new snapshots");
+ try {
+ return doReplaceSnapshots(workspaceId, envName, newSnapshots);
+ } catch (RuntimeException x) {
+ throw new SnapshotException(x.getLocalizedMessage(), x);
+ }
+ }
+
@Transactional
protected void doSave(SnapshotImpl snapshot) {
managerProvider.get().persist(snapshot);
@@ -131,4 +146,19 @@ public class JpaSnapshotDao implements SnapshotDao {
}
manager.remove(snapshot);
}
+
+ @Transactional
+ protected List doReplaceSnapshots(String workspaceId,
+ String envName,
+ Collection extends SnapshotImpl> newSnapshots) {
+ final EntityManager manager = managerProvider.get();
+ final List existing = manager.createNamedQuery("Snapshot.findByWorkspaceAndEnvironment", SnapshotImpl.class)
+ .setParameter("workspaceId", workspaceId)
+ .setParameter("envName", envName)
+ .getResultList();
+ existing.forEach(manager::remove);
+ manager.flush();
+ newSnapshots.forEach(manager::persist);
+ return existing;
+ }
}
diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java
index 70a17b591d..b9a51f503b 100644
--- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java
+++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/model/impl/SnapshotImpl.java
@@ -44,7 +44,12 @@ import java.util.Objects;
@NamedQuery(name = "Snapshot.findSnapshots",
query = "SELECT snapshot " +
"FROM Snapshot snapshot " +
- "WHERE snapshot.workspaceId = :workspaceId")
+ "WHERE snapshot.workspaceId = :workspaceId"),
+ @NamedQuery(name = "Snapshot.findByWorkspaceAndEnvironment",
+ query = "SELECT snapshot " +
+ "FROM Snapshot snapshot " +
+ "WHERE snapshot.workspaceId = :workspaceId " +
+ " AND snapshot.envName = :envName")
}
)
@Table(indexes = @Index(columnList = "workspaceId, envName, machineName", unique = true))
diff --git a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java
index de8391a576..4575995246 100644
--- a/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java
+++ b/wsmaster/che-core-api-machine/src/main/java/org/eclipse/che/api/machine/server/spi/SnapshotDao.java
@@ -14,6 +14,7 @@ import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.machine.server.exception.SnapshotException;
import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl;
+import java.util.Collection;
import java.util.List;
/**
@@ -86,4 +87,24 @@ public interface SnapshotDao {
* if other error occur
*/
void removeSnapshot(String snapshotId) throws NotFoundException, SnapshotException;
+
+ /**
+ * Replaces all the existing snapshots related to the given workspace
+ * with a new list of snapshots.
+ *
+ * @param workspaceId
+ * the id of the workspace to replace snapshots
+ * @param envName
+ * the name of the environment in workspace with given id
+ * which is used to search those snapshots that should be replaced
+ * @param newSnapshots
+ * the list of the snapshots which will be stored instead of existing ones
+ * @return the list of replaced(removed/old) snapshots for given workspace and environment,
+ * or an empty list when there is no a single snapshot for the given workspace
+ * @throws SnapshotException
+ * when any error occurs
+ */
+ List replaceSnapshots(String workspaceId,
+ String envName,
+ Collection extends SnapshotImpl> newSnapshots) throws SnapshotException;
}
diff --git a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java
index 2b19130516..651fdad1be 100644
--- a/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java
+++ b/wsmaster/che-core-api-machine/src/test/java/org/eclipse/che/api/machine/server/spi/tck/SnapshotDaoTest.java
@@ -10,6 +10,7 @@
*******************************************************************************/
package org.eclipse.che.api.machine.server.spi.tck;
+import com.google.common.collect.Sets;
import com.google.inject.Inject;
import org.eclipse.che.api.core.NotFoundException;
@@ -30,6 +31,7 @@ import java.util.HashSet;
import java.util.List;
import static java.util.Arrays.asList;
+import static java.util.Collections.singletonList;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;
@@ -180,6 +182,22 @@ public class SnapshotDaoTest {
snapshotDao.removeSnapshot(null);
}
+ @Test(dependsOnMethods = "shouldFindSnapshotsByWorkspaceAndNamespace")
+ public void replacesSnapshots() throws Exception {
+ final SnapshotImpl newSnapshot = createSnapshot("new-snapshot",
+ snapshots[0].getWorkspaceId(),
+ snapshots[0].getEnvName(),
+ snapshots[0].getMachineName());
+
+ final List replaced = snapshotDao.replaceSnapshots(newSnapshot.getWorkspaceId(),
+ newSnapshot.getEnvName(),
+ singletonList(newSnapshot));
+
+ assertEquals(new HashSet<>(replaced), Sets.newHashSet(snapshots[0], snapshots[1]));
+ assertEquals(new HashSet<>(snapshotDao.findSnapshots(snapshots[0].getWorkspaceId())),
+ Sets.newHashSet(newSnapshot, snapshots[2]));
+ }
+
@DataProvider(name = "missingSnapshots")
public Object[][] missingSnapshots() {
final SnapshotImpl snapshot = snapshots[0];
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java
index a9c3481e61..c7baf3807b 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceManager.java
@@ -26,10 +26,11 @@ 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;
import org.eclipse.che.api.core.notification.EventService;
-import org.eclipse.che.api.machine.server.spi.SnapshotDao;
+import org.eclipse.che.api.machine.server.exception.SnapshotException;
import org.eclipse.che.api.machine.server.model.impl.MachineImpl;
import org.eclipse.che.api.machine.server.model.impl.SnapshotImpl;
import org.eclipse.che.api.machine.server.spi.Instance;
+import org.eclipse.che.api.machine.server.spi.SnapshotDao;
import org.eclipse.che.api.workspace.server.WorkspaceRuntimes.RuntimeDescriptor;
import org.eclipse.che.api.workspace.server.event.WorkspaceCreatedEvent;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
@@ -43,11 +44,15 @@ import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.lang.concurrent.ThreadLocalPropagateContext;
import org.eclipse.che.commons.subject.Subject;
+import org.eclipse.che.dto.server.DtoFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.inject.Named;
import javax.inject.Singleton;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
@@ -57,7 +62,9 @@ import static com.google.common.base.MoreObjects.firstNonNull;
import static java.lang.Boolean.parseBoolean;
import static java.lang.String.format;
import static java.lang.System.currentTimeMillis;
+import static java.util.Arrays.asList;
import static java.util.Collections.emptyMap;
+import static java.util.Comparator.comparing;
import static java.util.Objects.requireNonNull;
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING;
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.STOPPED;
@@ -67,7 +74,6 @@ import static org.eclipse.che.api.workspace.shared.Constants.WORKSPACE_STOPPED_B
import static org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType.SNAPSHOT_CREATED;
import static org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType.SNAPSHOT_CREATING;
import static org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType.SNAPSHOT_CREATION_ERROR;
-import static org.eclipse.che.dto.server.DtoFactory.newDto;
/**
* Facade for Workspace related operations.
@@ -449,10 +455,32 @@ public class WorkspaceManager {
public void stopWorkspace(String workspaceId) throws ServerException,
NotFoundException,
ConflictException {
+ stopWorkspace(workspaceId, null);
+ }
+
+ /**
+ * Asynchronously stops the workspace,
+ * creates a snapshot of it if {@code createSnapshot} is set to true.
+ *
+ * @param workspaceId
+ * the id of the workspace to stop
+ * @param createSnapshot
+ * true if create snapshot, false if don't,
+ * null if default behaviour should be used
+ * @throws ServerException
+ * when any server error occurs
+ * @throws NullPointerException
+ * when {@code workspaceId} is null
+ * @throws NotFoundException
+ * when workspace {@code workspaceId} doesn't have runtime
+ */
+ public void stopWorkspace(String workspaceId, @Nullable Boolean createSnapshot) throws ConflictException,
+ NotFoundException,
+ ServerException {
requireNonNull(workspaceId, "Required non-null workspace id");
final WorkspaceImpl workspace = normalizeState(workspaceDao.get(workspaceId));
checkWorkspaceIsRunning(workspace, "stop");
- performAsyncStop(workspace);
+ performAsyncStop(workspace, createSnapshot);
}
/**
@@ -487,9 +515,9 @@ public class WorkspaceManager {
final WorkspaceImpl workspace = normalizeState(workspaceDao.get(workspaceId));
checkWorkspaceIsRunning(workspace, "create a snapshot of");
executor.execute(ThreadLocalPropagateContext.wrap(() -> {
- createSnapshotSync(workspace.getRuntime(),
- workspace.getNamespace(),
- workspaceId);
+ createSnapshotSync(workspace.getNamespace(),
+ workspaceId,
+ workspace.getRuntime().getActiveEnv());
}));
}
@@ -644,15 +672,20 @@ public class WorkspaceManager {
* attribute set to true) and then stops the workspace(even if snapshot creation failed).
*/
@VisibleForTesting
- void performAsyncStop(WorkspaceImpl workspace) throws ConflictException {
+ void performAsyncStop(WorkspaceImpl workspace, @Nullable Boolean createSnapshot) throws ConflictException {
checkWorkspaceIsRunning(workspace, "stop");
- final String autoSnapshotAttr = workspace.getAttributes().get(AUTO_CREATE_SNAPSHOT);
- boolean createSnapshot;
+
+ final boolean snapshotBeforeStop;
if (workspace.isTemporary()) {
- createSnapshot = false;
+ snapshotBeforeStop = false;
+ } else if (createSnapshot != null) {
+ snapshotBeforeStop = createSnapshot;
+ } else if (workspace.getAttributes().containsKey(AUTO_CREATE_SNAPSHOT)) {
+ snapshotBeforeStop = parseBoolean(workspace.getAttributes().get(AUTO_CREATE_SNAPSHOT));
} else {
- createSnapshot = autoSnapshotAttr == null ? defaultAutoSnapshot : parseBoolean(autoSnapshotAttr);
+ snapshotBeforeStop = defaultAutoSnapshot;
}
+
executor.execute(ThreadLocalPropagateContext.wrap(() -> {
final String stoppedBy = sessionUserNameOr(workspace.getAttributes().get(WORKSPACE_STOPPED_BY));
LOG.info("Workspace '{}:{}' with id '{}' is being stopped by user '{}'",
@@ -660,7 +693,9 @@ public class WorkspaceManager {
workspace.getConfig().getName(),
workspace.getId(),
firstNonNull(stoppedBy, "undefined"));
- if (createSnapshot && !createSnapshotSync(workspace.getRuntime(), workspace.getNamespace(), workspace.getId())) {
+ if (snapshotBeforeStop && !createSnapshotSync(workspace.getNamespace(),
+ workspace.getId(),
+ workspace.getRuntime().getActiveEnv())) {
LOG.warn("Could not create a snapshot of the workspace '{}:{}' with workspace id '{}'. The workspace will be stopped",
workspace.getNamespace(),
workspace.getConfig().getName(),
@@ -702,81 +737,81 @@ public class WorkspaceManager {
* otherwise returns false.
*/
@VisibleForTesting
- boolean createSnapshotSync(WorkspaceRuntimeImpl runtime, String namespace, String workspaceId) {
- eventService.publish(newDto(WorkspaceStatusEvent.class)
- .withEventType(SNAPSHOT_CREATING)
- .withWorkspaceId(workspaceId));
- String devMachineSnapshotFailMessage = null;
- for (MachineImpl machine : runtime.getMachines()) {
- String error = replaceSnapshot(machine, namespace);
- if (error != null && machine.getConfig().isDev()) {
- devMachineSnapshotFailMessage = error;
- }
- }
- if (devMachineSnapshotFailMessage != null) {
- eventService.publish(newDto(WorkspaceStatusEvent.class)
- .withEventType(SNAPSHOT_CREATION_ERROR)
- .withWorkspaceId(workspaceId)
- .withError(devMachineSnapshotFailMessage));
- } else {
- eventService.publish(newDto(WorkspaceStatusEvent.class)
- .withEventType(SNAPSHOT_CREATED)
- .withWorkspaceId(workspaceId));
- }
- return devMachineSnapshotFailMessage == null;
- }
-
- private String replaceSnapshot(MachineImpl machine, String namespace) {
+ boolean createSnapshotSync(String namespace, String workspaceId, String envName) {
try {
+ runtimes.beginSnapshotting(workspaceId);
+ } catch (NotFoundException | ConflictException x) {
+ LOG.warn("Couldn't start snapshot creation of workspace '{}' due to error: '{}'",
+ workspaceId,
+ x.getMessage());
+ return false;
+ }
+
+ publishEvent(SNAPSHOT_CREATING, workspaceId);
+
+ final List machines;
+ try {
+ machines = runtimes.get(workspaceId).getRuntime().getMachines();
+ } catch (Exception x) {
+ throw new IllegalStateException(x.getLocalizedMessage(), x);
+ }
+
+ LOG.info("Creating snapshot of workspace '{}', machines to snapshot: '{}'", workspaceId, machines.size());
+ final List newSnapshots = new ArrayList<>(machines.size());
+ Collections.sort(machines, comparing(m -> !m.getConfig().isDev(), Boolean::compare));
+ for (MachineImpl machine : machines) {
try {
- SnapshotImpl oldSnapshot = snapshotDao.getSnapshot(machine.getWorkspaceId(),
- machine.getEnvName(),
- machine.getConfig().getName());
- snapshotDao.removeSnapshot(oldSnapshot.getId());
-
- runtimes.removeSnapshot(oldSnapshot);
- } catch (NotFoundException ignored) {
- // Do nothing if no snapshot found
+ newSnapshots.add(runtimes.saveMachine(namespace, workspaceId, machine.getId()));
+ } catch (Exception x) {
+ if (machine.getConfig().isDev()) {
+ runtimes.finishSnapshotting(workspaceId);
+ publishEvent(SNAPSHOT_CREATION_ERROR, workspaceId, x.getMessage());
+ return false;
+ }
+ LOG.warn(format("Couldn't create snapshot of machine '%s:%s:%s' in workspace '%s'",
+ namespace,
+ machine.getEnvName(),
+ machine.getConfig().getName(),
+ workspaceId));
}
+ }
- SnapshotImpl snapshot = null;
+ try {
+ LOG.info("Saving new snapshots metadata, workspace id '{}'", workspaceId);
+ final List removed = snapshotDao.replaceSnapshots(workspaceId, envName, newSnapshots);
+ if (!removed.isEmpty()) {
+ LOG.info("Removing old snapshots, workspace id '{}', snapshots to remove '{}'", workspaceId, removed.size());
+ removeSnapshotsBinaries(removed);
+ }
+ } catch (SnapshotException x) {
+ LOG.error(format("Couldn't remove existing snapshots metadata for workspace '%s'", workspaceId), x);
+ LOG.info("Removing newly created snapshots, workspace id '{}', snapshots to remove '{}'", workspaceId, newSnapshots.size());
+ removeSnapshotsBinaries(newSnapshots);
+ runtimes.finishSnapshotting(workspaceId);
+ publishEvent(SNAPSHOT_CREATION_ERROR, workspaceId, x.getMessage());
+ return false;
+ }
+
+ runtimes.finishSnapshotting(workspaceId);
+ publishEvent(SNAPSHOT_CREATED, workspaceId);
+
+ return true;
+ }
+
+ private void removeSnapshotsBinaries(Collection extends SnapshotImpl> snapshots) {
+ for (SnapshotImpl snapshot : snapshots) {
try {
- snapshot = runtimes.saveMachine(namespace,
- machine.getWorkspaceId(),
- machine.getId());
- // check if the workspace exists before creating a snapshot,
- // if it is not an integrity constraint violation exception will occur,
- // this may happen when workspace stop called simultaneously.
- // The issue https://github.com/eclipse/che/issues/2683 should fix it
- // in a way that it won't be possible to snapshot workspace simultaneously.
- if (exists(machine.getWorkspaceId())) {
- snapshotDao.saveSnapshot(snapshot);
- } else {
- LOG.warn("Snapshot for a workspace '{}' won't be saved, as the workspace doesn't exist anymore",
- machine.getWorkspaceId());
- runtimes.removeSnapshot(snapshot);
- }
- } catch (ApiException e) {
- if (snapshot != null) {
- try {
- runtimes.removeSnapshot(snapshot);
- } catch (ApiException e1) {
- LOG.error(format("Snapshot removal failed. Snapshot: %s. Error: %s",
- snapshot,
- e1.getLocalizedMessage()),
- e1);
- }
- }
- throw e;
+ runtimes.removeSnapshot(snapshot);
+ } catch (ServerException | NotFoundException x) {
+ LOG.error(format("Couldn't remove snapshot '%s', workspace id '%s'",
+ snapshot.getId(),
+ snapshot.getWorkspaceId()),
+ x);
}
-
- return null;
- } catch (ApiException apiEx) {
- LOG.error("Snapshot creation failed. Error: " + apiEx.getLocalizedMessage(), apiEx);
- return apiEx.getLocalizedMessage();
}
}
+
@VisibleForTesting
void checkWorkspaceIsRunning(WorkspaceImpl workspace, String operation) throws ConflictException {
if (workspace.getStatus() != RUNNING) {
@@ -808,6 +843,17 @@ public class WorkspaceManager {
}
}
+ private void publishEvent(EventType type, String workspaceId, String error) {
+ eventService.publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(type)
+ .withWorkspaceId(workspaceId)
+ .withError(error));
+ }
+
+ private void publishEvent(EventType type, String workspaceId) {
+ publishEvent(type, workspaceId, null);
+ }
+
private WorkspaceImpl normalizeState(WorkspaceImpl workspace, RuntimeDescriptor descriptor) {
if (descriptor != null) {
workspace.setStatus(descriptor.getRuntimeStatus());
@@ -856,14 +902,4 @@ public class WorkspaceManager {
final String namespace = nsPart.isEmpty() ? sessionUser().getUserName() : nsPart;
return workspaceDao.get(wsName, namespace);
}
-
- /** Returns true if workspace exists and false otherwise. */
- private boolean exists(String workspaceId) throws ServerException {
- try {
- workspaceDao.get(workspaceId);
- } catch (NotFoundException x) {
- return false;
- }
- return true;
- }
}
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java
index 7425277f6d..a3c9b1570d 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimes.java
@@ -63,6 +63,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static java.lang.String.format;
+import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING;
+import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.SNAPSHOTTING;
import static org.eclipse.che.api.machine.shared.Constants.ENVIRONMENT_OUTPUT_CHANNEL_TEMPLATE;
import static org.eclipse.che.dto.server.DtoFactory.newDto;
import static org.slf4j.LoggerFactory.getLogger;
@@ -401,10 +403,7 @@ public class WorkspaceRuntimes {
NotFoundException {
try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) {
- WorkspaceState workspaceState = workspaces.get(workspaceId);
- if (workspaceState == null || workspaceState.status != WorkspaceStatus.RUNNING) {
- throw new ConflictException(format("Environment of workspace '%s' is not running", workspaceId));
- }
+ getRunningState(workspaceId);
}
List agents = Collections.singletonList("org.eclipse.che.terminal");
@@ -413,7 +412,7 @@ public class WorkspaceRuntimes {
try (StripedLocks.WriteLock lock = stripedLocks.acquireWriteLock(workspaceId)) {
WorkspaceState workspaceState = workspaces.get(workspaceId);
- if (workspaceState == null || workspaceState.status != WorkspaceStatus.RUNNING) {
+ if (workspaceState == null || workspaceState.status != RUNNING) {
try {
environmentEngine.stopMachine(workspaceId, instance.getId());
} catch (NotFoundException | ServerException | ConflictException e) {
@@ -426,6 +425,41 @@ public class WorkspaceRuntimes {
return instance;
}
+ /**
+ * Changes workspace runtimes status from RUNNING to SNAPSHOTTING.
+ *
+ * @param workspaceId
+ * the id of the workspace to begin snapshotting for
+ * @throws NotFoundException
+ * when workspace with such id doesn't have runtime
+ * @throws ConflictException
+ * when workspace status is different from SNAPSHOTTING
+ * @see WorkspaceStatus#SNAPSHOTTING
+ */
+ public void beginSnapshotting(String workspaceId) throws NotFoundException, ConflictException {
+ try (StripedLocks.WriteLock ignored = stripedLocks.acquireWriteLock(workspaceId)) {
+ getRunningState(workspaceId).status = SNAPSHOTTING;
+ }
+ }
+
+ /**
+ * Changes workspace runtimes status from SNAPSHOTTING back to RUNNING.
+ * This method won't affect workspace runtime or throw any exception
+ * if workspace is not in running status or doesn't have runtime.
+ *
+ * @param workspaceId
+ * the id of the workspace to finish snapshotting for
+ * @see WorkspaceStatus#SNAPSHOTTING
+ */
+ public void finishSnapshotting(String workspaceId) {
+ try (StripedLocks.WriteLock ignored = stripedLocks.acquireWriteLock(workspaceId)) {
+ final WorkspaceState state = workspaces.get(workspaceId);
+ if (state != null && state.status == SNAPSHOTTING) {
+ state.status = RUNNING;
+ }
+ }
+ }
+
/**
* Stops machine in a running environment.
*
@@ -447,7 +481,7 @@ public class WorkspaceRuntimes {
ConflictException {
try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) {
WorkspaceState workspaceState = workspaces.get(workspaceId);
- if (workspaceState == null || workspaceState.status != WorkspaceStatus.RUNNING) {
+ if (workspaceState == null || workspaceState.status != RUNNING) {
throw new ConflictException(format("Environment of workspace '%s' is not running", workspaceId));
}
}
@@ -479,8 +513,8 @@ public class WorkspaceRuntimes {
try (StripedLocks.ReadLock lock = stripedLocks.acquireReadLock(workspaceId)) {
WorkspaceState workspaceState = workspaces.get(workspaceId);
- if (workspaceState == null || workspaceState.status != WorkspaceStatus.RUNNING) {
- throw new ConflictException(format("Environment of workspace '%s' is not running", workspaceId));
+ if (workspaceState == null || !(workspaceState.status == SNAPSHOTTING || workspaceState.status == RUNNING)) {
+ throw new ConflictException(format("Environment of workspace '%s' is not running or snapshotting", workspaceId));
}
}
return environmentEngine.saveSnapshot(namespace, workspaceId, machineId);
@@ -549,7 +583,7 @@ public class WorkspaceRuntimes {
.build());
try (StripedLocks.WriteAllLock lock = stripedLocks.acquireWriteAllLock()) {
for (Map.Entry workspace : workspaces.entrySet()) {
- if (workspace.getValue().status.equals(WorkspaceStatus.RUNNING) ||
+ if (workspace.getValue().status.equals(RUNNING) ||
workspace.getValue().status.equals(WorkspaceStatus.STARTING)) {
stopEnvExecutor.execute(() -> {
try {
@@ -586,29 +620,30 @@ public class WorkspaceRuntimes {
.withError(error));
}
- private Instance getDevMachine(List machines) throws ServerException {
- Optional devMachineOpt = machines.stream()
- .filter(machine -> machine.getConfig().isDev())
- .findAny();
-
- if (devMachineOpt.isPresent()) {
- return devMachineOpt.get();
- }
- throw new ServerException(
- "Environment has booted but it doesn't contain dev machine. Environment has been stopped.");
- }
-
private void ensurePreDestroyIsNotExecuted() throws ServerException {
if (isPreDestroyInvoked) {
throw new ServerException("Could not perform operation because application server is stopping");
}
}
+ private WorkspaceState getRunningState(String workspaceId) throws NotFoundException, ConflictException {
+ final WorkspaceState state = workspaces.get(workspaceId);
+ if (state == null) {
+ throw new NotFoundException("Workspace with id '" + workspaceId + "' is not running");
+ }
+ if (state.getStatus() != RUNNING) {
+ throw new ConflictException(format("Workspace with id '%s' is not in 'RUNNING', it's status is '%s'",
+ workspaceId,
+ state.getStatus()));
+ }
+ return state;
+ }
+
protected void launchAgents(Instance instance, List agents) throws ServerException {
try {
for (AgentKey agentKey : agentSorter.sort(agents)) {
LOG.info("Launching '{}' agent", agentKey.getName());
-
+
Agent agent = agentRegistry.getAgent(agentKey);
AgentLauncher launcher = launcherFactory.find(agentKey.getName(), instance.getConfig().getType());
launcher.launch(instance, agent);
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java
index bfa25feaa2..53fb01531e 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceService.java
@@ -346,11 +346,13 @@ public class WorkspaceService extends Service {
@ApiResponse(code = 404, message = "The workspace with specified id doesn't exist"),
@ApiResponse(code = 403, message = "The user is not workspace owner"),
@ApiResponse(code = 500, message = "Internal server error occurred")})
- public void stop(@ApiParam("The workspace id") @PathParam("id") String id) throws ForbiddenException,
- NotFoundException,
- ServerException,
- ConflictException {
- workspaceManager.stopWorkspace(id);
+ public void stop(@ApiParam("The workspace id") @PathParam("id") String id,
+ @ApiParam("Whether to snapshot workspace before stopping it")
+ @QueryParam("create-snapshot") Boolean createSnapshot) throws ForbiddenException,
+ NotFoundException,
+ ServerException,
+ ConflictException {
+ workspaceManager.stopWorkspace(id, createSnapshot);
}
@POST
@@ -506,10 +508,10 @@ public class WorkspaceService extends Service {
@ApiParam(value = "The name of the environment", required = true)
@QueryParam("name")
String envName) throws ServerException,
- BadRequestException,
- NotFoundException,
- ConflictException,
- ForbiddenException {
+ BadRequestException,
+ NotFoundException,
+ ConflictException,
+ ForbiddenException {
requiredNotNull(newEnvironment, "New environment");
requiredNotNull(envName, "New environment name");
final WorkspaceImpl workspace = workspaceManager.getWorkspace(id);
@@ -673,7 +675,7 @@ public class WorkspaceService extends Service {
@ApiResponse(code = 404, message = "The workspace with specified id does not exist"),
@ApiResponse(code = 500, message = "Internal server error occurred")})
public WsAgentHealthStateDto checkAgentHealth(@ApiParam(value = "Workspace id")
- @PathParam("id") String key) throws NotFoundException, ServerException{
+ @PathParam("id") String key) throws NotFoundException, ServerException {
final WorkspaceImpl workspace = workspaceManager.getWorkspace(key);
if (WorkspaceStatus.RUNNING != workspace.getStatus()) {
return newDto(WsAgentHealthStateDto.class).withWorkspaceStatus(workspace.getStatus());
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java
index fd2e2a08df..1ac45747c3 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/WorkspaceConfigImpl.java
@@ -204,13 +204,14 @@ public class WorkspaceConfigImpl implements WorkspaceConfig {
@Override
public String toString() {
- return "UsersWorkspaceImpl{" +
+ return "WorkspaceConfigImpl{" +
+ "id=" + id +
", name='" + name + '\'' +
+ ", description='" + description + '\'' +
", defaultEnv='" + defaultEnv + '\'' +
", commands=" + commands +
", projects=" + projects +
", environments=" + environments +
- ", description='" + description + '\'' +
'}';
}
diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java
index aafdb818ce..0b70fe28fc 100644
--- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java
+++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceManagerTest.java
@@ -41,6 +41,7 @@ import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
import org.eclipse.che.commons.env.EnvironmentContext;
import org.eclipse.che.commons.subject.Subject;
import org.eclipse.che.commons.subject.SubjectImpl;
+import org.eclipse.che.dto.server.DtoFactory;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InOrder;
@@ -51,11 +52,14 @@ import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.UUID;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING;
@@ -77,6 +81,7 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
@@ -99,23 +104,23 @@ public class WorkspaceManagerTest {
private static final String NAMESPACE_2 = "userNS2";
@Mock
- private EventService eventService;
+ private EventService eventService;
@Mock
- private WorkspaceDao workspaceDao;
+ private WorkspaceDao workspaceDao;
@Mock
- private WorkspaceValidator workspaceConfigValidator;
+ private WorkspaceValidator workspaceConfigValidator;
@Mock
- private MachineProcessManager client;
+ private MachineProcessManager client;
@Mock
- private WorkspaceRuntimes runtimes;
+ private WorkspaceRuntimes runtimes;
@Mock
- private AccountManager accountManager;
+ private AccountManager accountManager;
@Mock
- private SnapshotDao snapshotDao;
- @Mock
- private WorkspaceFilesCleaner workspaceFilesCleaner;
+ private SnapshotDao snapshotDao;
@Captor
- private ArgumentCaptor workspaceCaptor;
+ private ArgumentCaptor workspaceCaptor;
+ @Captor
+ private ArgumentCaptor> snapshotsCaptor;
private WorkspaceManager workspaceManager;
@@ -530,62 +535,105 @@ public class WorkspaceManagerTest {
}
@Test
- public void shouldNotCreateSnapshotIfWorkspaceIsTemporaryAndAutoCreateSnapshotActivated() throws Exception {
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- workspace.getAttributes().put(Constants.AUTO_CREATE_SNAPSHOT, "true");
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- workspace.setTemporary(true);
+ public void createsSnapshotBeforeStoppingWorkspace() throws Exception {
+ final WorkspaceImpl workspace = createRunningWorkspace();
workspaceManager.stopWorkspace(workspace.getId());
- verify(workspaceManager, timeout(2000).never()).createSnapshotSync(anyObject(), anyString(), anyString());
- verify(runtimes, timeout(2000)).stop(workspace.getId());
+ verify(runtimes, timeout(2000)).beginSnapshotting(workspace.getId());
+ verify(runtimes, timeout(2000)).finishSnapshotting(workspace.getId());
+ final Iterator machineIt = workspace.getRuntime().getMachines().iterator();
+ verify(runtimes).saveMachine(workspace.getNamespace(), workspace.getId(), machineIt.next().getId());
+ verify(runtimes).saveMachine(workspace.getNamespace(), workspace.getId(), machineIt.next().getId());
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATING)
+ .withWorkspaceId(workspace.getId()));
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATED)
+ .withWorkspaceId(workspace.getId()));
}
@Test
- public void shouldNotCreateSnapshotIfWorkspaceIsTemporaryAndAutoCreateSnapshotDisactivated() throws Exception {
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- workspace.getAttributes().put(Constants.AUTO_CREATE_SNAPSHOT, "false");
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- workspace.setTemporary(true);
+ public void failsToCreateSnapshotWhenDevMachineSnapshottingFailed() throws Exception {
+ final WorkspaceImpl workspace = createRunningWorkspace();
+ when(runtimes.saveMachine(any(), any(), any())).thenThrow( new ServerException("test"));
workspaceManager.stopWorkspace(workspace.getId());
- verify(workspaceManager, timeout(2000).never()).createSnapshotSync(anyObject(), anyString(), anyString());
- verify(runtimes, timeout(2000)).stop(workspace.getId());
+ verify(runtimes, timeout(2000)).beginSnapshotting(workspace.getId());
+ verify(runtimes, timeout(2000)).finishSnapshotting(workspace.getId());
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATING)
+ .withWorkspaceId(workspace.getId()));
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATION_ERROR)
+ .withWorkspaceId(workspace.getId())
+ .withError("test"));
}
@Test
- public void shouldCreateWorkspaceSnapshotBeforeStoppingWorkspace() throws Exception {
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- workspace.getAttributes().put(Constants.AUTO_CREATE_SNAPSHOT, "true");
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
+ public void removesNewlyCreatedSnapshotsWhenFailedToSaveTheirsMetadata() throws Exception {
+ final WorkspaceImpl workspace = createRunningWorkspace();
+ when(snapshotDao.replaceSnapshots(eq(workspace.getId()),
+ eq(workspace.getRuntime().getActiveEnv()),
+ anyObject())).thenThrow(new SnapshotException("test"));
workspaceManager.stopWorkspace(workspace.getId());
- verify(workspaceManager, timeout(2000)).createSnapshotSync(anyObject(), anyString(), anyString());
- verify(runtimes, timeout(2000)).stop(workspace.getId());
+ verify(runtimes, timeout(2000)).beginSnapshotting(workspace.getId());
+ verify(runtimes, timeout(2000)).finishSnapshotting(workspace.getId());
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATING)
+ .withWorkspaceId(workspace.getId()));
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATION_ERROR)
+ .withWorkspaceId(workspace.getId())
+ .withError("test"));
+ verify(snapshotDao).replaceSnapshots(eq(workspace.getId()),
+ eq(workspace.getRuntime().getActiveEnv()),
+ snapshotsCaptor.capture());
+ final Iterator snapshotsIt = snapshotsCaptor.getValue().iterator();
+ verify(runtimes).removeSnapshot(snapshotsIt.next());
+ verify(runtimes).removeSnapshot(snapshotsIt.next());
+ }
+
+ @Test
+ public void removesOldSnapshotsWhenNewSnapshotsMetadataSuccessfullySaved() throws Exception {
+ final WorkspaceImpl workspace = createRunningWorkspace();
+ final SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
+ when(snapshotDao.replaceSnapshots(eq(workspace.getId()),
+ eq(workspace.getRuntime().getActiveEnv()),
+ anyObject())).thenReturn(singletonList(oldSnapshot));
+
+ workspaceManager.stopWorkspace(workspace.getId());
+
+ verify(runtimes, timeout(2000)).beginSnapshotting(workspace.getId());
+ verify(runtimes, timeout(2000)).finishSnapshotting(workspace.getId());
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATING)
+ .withWorkspaceId(workspace.getId()));
+ verify(eventService).publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(SNAPSHOT_CREATED)
+ .withWorkspaceId(workspace.getId()));
+ verify(runtimes).removeSnapshot(oldSnapshot);
+ }
+
+ @Test
+ public void passedCreateSnapshotParameterIsUsedInPreferenceToAttribute() throws Exception {
+ final WorkspaceImpl workspace = createRunningWorkspace();
+
+ workspaceManager.stopWorkspace(workspace.getId(), false);
+
+ verify(runtimes, never()).beginSnapshotting(workspace.getId());
+ }
+
+ @Test
+ public void passedNullCreateSnapshotParameterIsIgnored() throws Exception {
+ final WorkspaceImpl workspace = createRunningWorkspace();
+
+ workspaceManager.stopWorkspace(workspace.getId(), null);
+
+ verify(runtimes, timeout(2000)).beginSnapshotting(workspace.getId());
}
@Test(expectedExceptions = ConflictException.class,
@@ -658,6 +706,46 @@ public class WorkspaceManagerTest {
assertEquals(snapshots.get(0), wsSnapshot);
}
+ @Test
+ public void shouldNotCreateSnapshotIfWorkspaceIsTemporaryAndAutoCreateSnapshotActivated() throws Exception {
+ final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
+ workspace.getAttributes().put(Constants.AUTO_CREATE_SNAPSHOT, "true");
+ when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
+ final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
+ when(runtimes.get(any())).thenReturn(descriptor);
+ SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
+ when(snapshotDao.getSnapshot(eq(workspace.getId()),
+ eq(workspace.getConfig().getDefaultEnv()),
+ anyString()))
+ .thenReturn(oldSnapshot);
+ workspace.setTemporary(true);
+
+ workspaceManager.stopWorkspace(workspace.getId());
+
+ verify(workspaceManager, timeout(2000).never()).createSnapshotSync(anyObject(), anyString(), anyString());
+ verify(runtimes, timeout(2000)).stop(workspace.getId());
+ }
+
+ @Test
+ public void shouldNotCreateSnapshotIfWorkspaceIsTemporaryAndAutoCreateSnapshotDisactivated() throws Exception {
+ final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
+ workspace.getAttributes().put(Constants.AUTO_CREATE_SNAPSHOT, "false");
+ when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
+ final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
+ when(runtimes.get(any())).thenReturn(descriptor);
+ SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
+ when(snapshotDao.getSnapshot(eq(workspace.getId()),
+ eq(workspace.getConfig().getDefaultEnv()),
+ anyString()))
+ .thenReturn(oldSnapshot);
+ workspace.setTemporary(true);
+
+ workspaceManager.stopWorkspace(workspace.getId());
+
+ verify(workspaceManager, timeout(2000).never()).createSnapshotSync(anyObject(), anyString(), anyString());
+ verify(runtimes, timeout(2000)).stop(workspace.getId());
+ }
+
@Test
public void shouldCreateWorkspaceSnapshotUsingDefaultValueForAutoRestore() throws Exception {
// given
@@ -682,7 +770,9 @@ public class WorkspaceManagerTest {
workspaceManager.stopWorkspace(workspace.getId());
// then
- verify(workspaceManager, timeout(2000)).createSnapshotSync(workspace.getRuntime(), workspace.getNamespace(), workspace.getId());
+ verify(workspaceManager, timeout(2000)).createSnapshotSync(workspace.getNamespace(),
+ workspace.getId(),
+ workspace.getRuntime().getActiveEnv());
verify(runtimes, timeout(2000)).stop(any());
}
@@ -838,9 +928,9 @@ public class WorkspaceManagerTest {
workspaceManager.createSnapshot(workspace.getId());
// then
- verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class),
- eq(workspace.getNamespace()),
- eq(workspace.getId()));
+ verify(workspaceManager, timeout(1_000)).createSnapshotSync(eq(workspace.getNamespace()),
+ eq(workspace.getId()),
+ anyString());
}
@Test(expectedExceptions = ConflictException.class,
@@ -856,29 +946,6 @@ public class WorkspaceManagerTest {
workspaceManager.createSnapshot(workspace.getId());
}
- @Test
- public void shouldSnapshotAllMachinesInWs() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(runtimes, timeout(1_000).times(2)).saveMachine(eq(workspace.getNamespace()),
- eq(workspace.getId()),
- anyString());
- verify(snapshotDao, timeout(1_000).times(2)).saveSnapshot(any(SnapshotImpl.class));
- }
-
@Test
public void shouldSendEventOnStartSnapshotSaving() throws Exception {
// given
@@ -923,228 +990,6 @@ public class WorkspaceManagerTest {
.withWorkspaceId(workspace.getId())));
}
- @Test
- public void shouldSendSnapshotSavingFailedEventIfDevMachineSnapshotSavingFailed() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- for (MachineImpl machine : descriptor.getRuntime().getMachines()) {
- if (machine.getConfig().isDev()) {
- when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId()))
- .thenThrow(new ServerException("test error"));
- }
- }
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(eventService, timeout(1_000)).publish(eq(newDto(WorkspaceStatusEvent.class)
- .withEventType(SNAPSHOT_CREATION_ERROR)
- .withWorkspaceId(workspace.getId())
- .withError("test error")));
- }
-
- @Test
- public void shouldNotSendSnapshotSavingFailedEventIfNonDevMachineSnapshotSavingFailed() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- for (MachineImpl machine : descriptor.getRuntime().getMachines()) {
- if (!machine.getConfig().isDev()) {
- when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId()))
- .thenThrow(new ServerException("test error"));
- }
- }
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(eventService, timeout(1_000)).publish(eq(newDto(WorkspaceStatusEvent.class)
- .withEventType(SNAPSHOT_CREATED)
- .withWorkspaceId(workspace.getId())));
- }
-
- @Test
- public void shouldReturnFalseOnFailureSnapshotSavingIfDevMachineSavingFailed() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- for (MachineImpl machine : descriptor.getRuntime().getMachines()) {
- if (machine.getConfig().isDev()) {
- when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId()))
- .thenThrow(new ServerException("test error"));
- }
- }
-
- // when
- boolean snapshotSavingStatus = workspaceManager.createSnapshotSync(
- new WorkspaceRuntimeImpl(descriptor.getRuntime()), workspace.getNamespace(), workspace.getId());
-
- // then
- assertFalse(snapshotSavingStatus);
- }
-
- @Test
- public void shouldReturnTrueOnSuccessfulSavingSnapshotsForSeveralMachines() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
-
- // when
- boolean snapshotSavingStatus = workspaceManager.createSnapshotSync(
- new WorkspaceRuntimeImpl(descriptor.getRuntime()), workspace.getNamespace(), workspace.getId());
-
- // then
- assertTrue(snapshotSavingStatus);
- // ensure that multiple machines were saved
- verify(snapshotDao, timeout(1_000).atLeast(2)).saveSnapshot(any(SnapshotImpl.class));
- }
-
- @Test
- public void shouldReturnTrueOnSavingSnapshotsForSeveralMachinesWhenNonDevMachineSavingFailed() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- for (MachineImpl machine : descriptor.getRuntime().getMachines()) {
- if (!machine.getConfig().isDev()) {
- when(runtimes.saveMachine(workspace.getNamespace(), workspace.getId(), machine.getId()))
- .thenThrow(new ServerException("test error"));
- }
- }
-
- // when
- boolean snapshotSavingStatus = workspaceManager.createSnapshotSync(
- new WorkspaceRuntimeImpl(descriptor.getRuntime()), workspace.getNamespace(), workspace.getId());
-
- // then
- assertTrue(snapshotSavingStatus);
- }
-
- @Test
- public void shouldRemoveRuntimeSnapshotIfSavingSnapshotInDaoFails() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- doThrow(new SnapshotException("test error")).when(snapshotDao).saveSnapshot(any(SnapshotImpl.class));
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(runtimes, timeout(1_000).times(2)).removeSnapshot(any(SnapshotImpl.class));
- }
-
- @Test
- public void shouldIgnoreNotFoundExceptionOnOldSnapshotRemoval1() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- doThrow(new NotFoundException("test error")).when(snapshotDao).removeSnapshot(anyString());
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class),
- eq(workspace.getNamespace()),
- eq(workspace.getId()));
- }
-
- @Test
- public void shouldIgnoreNotFoundExceptionOnOldSnapshotRemoval2() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- SnapshotImpl oldSnapshot = mock(SnapshotImpl.class);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenReturn(oldSnapshot);
- doThrow(new NotFoundException("test error")).when(runtimes).removeSnapshot(any(SnapshotImpl.class));
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class),
- eq(workspace.getNamespace()),
- eq(workspace.getId()));
- }
-
- @Test
- public void shouldIgnoreNotFoundExceptionOnOldSnapshotRemoval3() throws Exception {
- // given
- final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
- when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
- RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
- when(runtimes.get(any())).thenReturn(descriptor);
- when(snapshotDao.getSnapshot(eq(workspace.getId()),
- eq(workspace.getConfig().getDefaultEnv()),
- anyString()))
- .thenThrow(new NotFoundException("test error"));
-
- // when
- workspaceManager.createSnapshot(workspace.getId());
-
- // then
- verify(workspaceManager, timeout(1_000)).createSnapshotSync(any(WorkspaceRuntimeImpl.class),
- eq(workspace.getNamespace()),
- eq(workspace.getId()));
- }
-
@Test
public void shouldBeAbleToStopMachine() throws Exception {
// given
@@ -1206,22 +1051,64 @@ public class WorkspaceManagerTest {
verify(runtimes).getMachine(workspace.getId(), machine.getId());
}
- private RuntimeDescriptor createDescriptor(WorkspaceImpl workspace, WorkspaceStatus status) {
+ private RuntimeDescriptor createDescriptor(WorkspaceImpl workspace, WorkspaceStatus status)
+ throws ServerException, NotFoundException, ConflictException {
EnvironmentImpl environment = workspace.getConfig().getEnvironments().get(workspace.getConfig().getDefaultEnv());
assertNotNull(environment);
final WorkspaceRuntimeImpl runtime = new WorkspaceRuntimeImpl(workspace.getConfig().getDefaultEnv());
- MachineImpl machine = spy(createMachine(workspace.getId(), workspace.getConfig().getDefaultEnv(), true));
- runtime.getMachines().add(machine);
- MachineImpl machine2 = spy(createMachine(workspace.getId(), workspace.getConfig().getDefaultEnv(), false));
- runtime.getMachines().add(machine2);
+ final MachineImpl machine1 = spy(createMachine(workspace.getId(), workspace.getConfig().getDefaultEnv(), true));
+ final MachineImpl machine2 = spy(createMachine(workspace.getId(), workspace.getConfig().getDefaultEnv(), false));
+ final Map machines = new HashMap<>();
+ machines.put(machine1.getId(), machine1);
+ machines.put(machine2.getId(), machine2);
+ runtime.getMachines().addAll(machines.values());
+ runtime.setDevMachine(machine1);
+
+ when(runtimes.saveMachine(any(), any(), anyObject())).thenAnswer(inv -> {
+ final String machineId = (String)inv.getArguments()[2];
+ final MachineImpl machine = machines.get(machineId);
+ if (machine == null) {
+ return null;
+ }
+ return SnapshotImpl.builder()
+ .setWorkspaceId(machine.getWorkspaceId())
+ .useCurrentCreationDate()
+ .generateId()
+ .setDescription("test")
+ .setDev(machine.getConfig().isDev())
+ .setEnvName(machine.getEnvName())
+ .setMachineName(machine.getConfig().getName())
+ .build();
+ });
final RuntimeDescriptor descriptor = mock(RuntimeDescriptor.class);
when(descriptor.getRuntimeStatus()).thenReturn(status);
when(descriptor.getRuntime()).thenReturn(runtime);
+ workspace.setRuntime(runtime);
return descriptor;
}
+ private WorkspaceImpl createRunningWorkspace() throws ServerException, NotFoundException, ConflictException {
+ // should be snapshotted when stopped
+ final WorkspaceImpl workspace = workspaceManager.createWorkspace(createConfig(), NAMESPACE);
+ workspace.getAttributes().put(Constants.AUTO_CREATE_SNAPSHOT, "true");
+ when(workspaceDao.get(workspace.getId())).thenReturn(workspace);
+
+ // has runtime
+ final RuntimeDescriptor descriptor = createDescriptor(workspace, RUNNING);
+ when(runtimes.get(workspace.getId())).thenReturn(descriptor);
+
+ // doesn't have snapshots
+ when(snapshotDao.findSnapshots(workspace.getId())).thenReturn(emptyList());
+ when(snapshotDao.replaceSnapshots(eq(workspace.getId()),
+ eq(workspace.getRuntime().getActiveEnv()),
+ any())).thenReturn(emptyList());
+
+ return workspace;
+ }
+
+
private static WorkspaceConfigImpl createConfig() {
EnvironmentImpl environment = new EnvironmentImpl(new EnvironmentRecipeImpl("type",
"contentType",
diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java
index 2bcd4a9c87..170909a8eb 100644
--- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java
+++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceRuntimesTest.java
@@ -36,8 +36,11 @@ import org.eclipse.che.api.workspace.server.model.impl.EnvironmentImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceRuntimeImpl;
+import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent.EventType;
import org.eclipse.che.commons.lang.NameGenerator;
+import org.eclipse.che.dto.server.DtoFactory;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.testng.MockitoTestNGListener;
import org.testng.annotations.BeforeMethod;
@@ -51,23 +54,29 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import static java.lang.String.format;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap;
import static org.eclipse.che.api.core.model.workspace.WorkspaceStatus.RUNNING;
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.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.fail;
/**
* @author Yevhenii Voevodin
@@ -436,8 +445,8 @@ public class WorkspaceRuntimesTest {
verify(runtimes).launchAgents(instance, singletonList("org.eclipse.che.terminal"));
}
- @Test(expectedExceptions = ConflictException.class,
- expectedExceptionsMessageRegExp = "Environment of workspace '.*' is not running")
+ @Test(expectedExceptions = NotFoundException.class,
+ expectedExceptionsMessageRegExp = "Workspace with id '.*' is not running")
public void shouldNotStartMachineIfEnvironmentIsNotRunning() throws Exception {
// when
MachineConfigImpl config = createConfig(false);
@@ -493,7 +502,7 @@ public class WorkspaceRuntimesTest {
}
@Test(expectedExceptions = ConflictException.class,
- expectedExceptionsMessageRegExp = "Environment of workspace '.*' is not running")
+ expectedExceptionsMessageRegExp = "Environment of workspace 'workspaceId' is not running or snapshotting")
public void shouldNotSaveMachineIfEnvironmentIsNotRunning() throws Exception {
// when
runtimes.saveMachine("namespace", "workspaceId", "machineId");
@@ -572,6 +581,72 @@ public class WorkspaceRuntimesTest {
assertEquals(actualWorkspaces, expectedWorkspaces);
}
+ @Test
+ public void changesStatusFromRunningToSnapshotting() throws Exception {
+ final WorkspaceImpl workspace = createWorkspace();
+ runtimes.start(workspace, workspace.getConfig().getDefaultEnv(), false);
+
+ runtimes.beginSnapshotting(workspace.getId());
+
+ assertEquals(runtimes.get(workspace.getId()).getRuntimeStatus(), WorkspaceStatus.SNAPSHOTTING);
+ }
+
+ @Test
+ public void changesStatusFromSnapshottingToRunning() throws Exception {
+ final WorkspaceImpl workspace = createWorkspace();
+ runtimes.start(workspace, workspace.getConfig().getDefaultEnv(), false);
+ runtimes.beginSnapshotting(workspace.getId());
+
+ runtimes.finishSnapshotting(workspace.getId());
+
+ assertEquals(runtimes.get(workspace.getId()).getRuntimeStatus(), WorkspaceStatus.RUNNING);
+ }
+
+ @Test
+ public void doesNothingWhenWorkspaceDoesNotHaveRuntimeAndFinishSnapshottingIsCalled() throws Exception {
+ runtimes.finishSnapshotting("fake");
+ }
+
+ @Test
+ public void doesNothingWhenWorkspaceStatusIsNotSnapshottingAndFinishSnapshottingIsCalled() throws Exception {
+ final WorkspaceImpl workspace = createWorkspace();
+ runtimes.start(workspace, workspace.getConfig().getDefaultEnv(), false);
+
+ runtimes.finishSnapshotting(workspace.getId());
+
+ assertEquals(runtimes.get(workspace.getId()).getRuntimeStatus(), WorkspaceStatus.RUNNING);
+ }
+
+ @Test(expectedExceptions = NotFoundException.class,
+ expectedExceptionsMessageRegExp = "Workspace with id 'non-existing' is not running")
+ public void throwsNotFoundExceptionWhenBeginningSnapshottingForNonExistingWorkspace() throws Exception {
+ runtimes.beginSnapshotting("non-existing");
+ }
+
+ @Test
+ public void throwsConflictExceptionWhenBeginningSnapshottingForNotRunningWorkspace() throws Exception {
+ final WorkspaceImpl workspace = createWorkspace();
+
+ doAnswer(inv -> {
+ // checking exception here
+ try {
+ runtimes.beginSnapshotting(workspace.getId());
+ fail("Expected to get an exception");
+ } catch (ConflictException x) {
+ assertEquals(x.getMessage(), format("Workspace with id '%s' is not in '%s', it's status is '%s'",
+ workspace.getId(),
+ WorkspaceStatus.RUNNING,
+ WorkspaceStatus.STARTING));
+ }
+ return null;
+ }).when(eventService)
+ .publish(DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withEventType(EventType.STARTING)
+ .withWorkspaceId(workspace.getId()));
+
+ runtimes.start(workspace, workspace.getConfig().getDefaultEnv(), false);
+ }
+
private static Instance createMachine(boolean isDev) {
return createMachine(createConfig(isDev));
}
diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java
index 0d8c27ae31..56c41eaa9f 100644
--- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java
+++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceServiceTest.java
@@ -471,7 +471,7 @@ public class WorkspaceServiceTest {
.delete(SECURE_PATH + "/workspace/" + workspace.getId() + "/runtime");
assertEquals(response.getStatusCode(), 204);
- verify(wsManager).stopWorkspace(workspace.getId());
+ verify(wsManager).stopWorkspace(workspace.getId(), null);
}
@Test
diff --git a/wsmaster/wsmaster-local/pom.xml b/wsmaster/wsmaster-local/pom.xml
index 1665ae9f3e..c52148a8cc 100644
--- a/wsmaster/wsmaster-local/pom.xml
+++ b/wsmaster/wsmaster-local/pom.xml
@@ -36,26 +36,10 @@
com.google.inject
guice
-
- com.google.inject.extensions
- guice-persist
-
-
- com.jcraft
- jsch
-
-
- commons-fileupload
- commons-fileupload
-
commons-io
commons-io
-
- io.swagger
- swagger-annotations
-
javax.annotation
javax.annotation-api
@@ -64,14 +48,6 @@
javax.inject
javax.inject
-
- javax.validation
- validation-api
-
-
- javax.ws.rs
- javax.ws.rs-api
-
org.eclipse.che.core
che-core-api-account
@@ -80,22 +56,10 @@
org.eclipse.che.core
che-core-api-core
-
- org.eclipse.che.core
- che-core-api-dto
-
-
- org.eclipse.che.core
- che-core-api-jdbc
-
org.eclipse.che.core
che-core-api-machine
-
- org.eclipse.che.core
- che-core-api-machine-shared
-
org.eclipse.che.core
che-core-api-model
@@ -104,18 +68,10 @@
org.eclipse.che.core
che-core-api-ssh
-
- org.eclipse.che.core
- che-core-api-ssh-shared
-
org.eclipse.che.core
che-core-api-user
-
- org.eclipse.che.core
- che-core-api-user-shared
-
org.eclipse.che.core
che-core-api-workspace
@@ -128,22 +84,10 @@
org.eclipse.che.core
che-core-commons-lang
-
- org.eclipse.persistence
- eclipselink
-
-
- org.eclipse.persistence
- javax.persistence
-
org.everrest
everrest-core
-
- org.everrest
- everrest-websockets
-
org.slf4j
slf4j-api
@@ -218,26 +162,4 @@
test
-
-
-
- org.apache.maven.plugins
- maven-dependency-plugin
-
-
-
- unpack-dependencies
-
-
- ${project.build.testOutputDirectory}
- che-core-api-user,
- che-core-api-machine,
- che-core-api-ssh
- test
-
-
-
-
-
-
diff --git a/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java b/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java
index 925763f929..951128aa5c 100644
--- a/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java
+++ b/wsmaster/wsmaster-local/src/main/java/org/eclipse/che/api/local/LocalSnapshotDaoImpl.java
@@ -27,6 +27,7 @@ import javax.annotation.PreDestroy;
import javax.inject.Inject;
import javax.inject.Singleton;
import java.io.IOException;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -119,6 +120,12 @@ public class LocalSnapshotDaoImpl implements SnapshotDao {
snapshots.remove(snapshotId);
}
+ @Override
+ public List replaceSnapshots(String workspaceId, String envName, Collection extends SnapshotImpl> newSnapshots)
+ throws SnapshotException {
+ throw new RuntimeException("Not implemented");
+ }
+
@PostConstruct
public synchronized void loadSnapshots() {
snapshots.putAll(snapshotStorage.loadMap(new TypeToken