diff --git a/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml b/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml
index 712e1fe5d2..e0a3cc5c63 100644
--- a/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml
+++ b/assembly/assembly-wsmaster-war/src/main/resources/META-INF/persistence.xml
@@ -30,6 +30,7 @@
org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute
org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl
org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl
+ org.eclipse.che.api.workspace.server.model.impl.VolumeImpl
org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl
org.eclipse.che.api.workspace.server.model.impl.CommandImpl
diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java
index 162377c7de..e8595f73f7 100644
--- a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java
+++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/MachineConfig.java
@@ -44,4 +44,7 @@ public interface MachineConfig {
/** Returns attributes of resources of machine. */
Map getAttributes();
+
+ /** Returns volumes of machine */
+ Map getVolumes();
}
diff --git a/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Volume.java b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Volume.java
new file mode 100644
index 0000000000..1eaedf08be
--- /dev/null
+++ b/core/che-core-api-model/src/main/java/org/eclipse/che/api/core/model/workspace/config/Volume.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2012-2017 Red Hat, Inc.
+ * 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:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.core.model.workspace.config;
+
+/**
+ * Machine volume configuration.
+ *
+ * @author Alexander Garagatyi
+ */
+public interface Volume {
+
+ /** Mount path of the volume in the machine */
+ String getPath();
+}
diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/MachineConfigImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/MachineConfigImpl.java
index 7e119c1338..4b8ca2ddce 100644
--- a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/MachineConfigImpl.java
+++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/MachineConfigImpl.java
@@ -17,6 +17,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.eclipse.che.api.core.model.workspace.config.MachineConfig;
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
+import org.eclipse.che.api.core.model.workspace.config.Volume;
public class MachineConfigImpl implements MachineConfig {
@@ -24,12 +25,14 @@ public class MachineConfigImpl implements MachineConfig {
private Map env;
private Map attributes;
private Map servers;
+ private Map volumes;
public MachineConfigImpl(
List installers,
Map servers,
Map env,
- Map attributes) {
+ Map attributes,
+ Map volumes) {
if (installers != null) {
this.installers = new ArrayList<>(installers);
}
@@ -48,10 +51,23 @@ public class MachineConfigImpl implements MachineConfig {
if (attributes != null) {
this.attributes = new HashMap<>(attributes);
}
+ if (volumes != null) {
+ this.volumes =
+ volumes
+ .entrySet()
+ .stream()
+ .collect(
+ Collectors.toMap(Map.Entry::getKey, entry -> new VolumeImpl(entry.getValue())));
+ }
}
public MachineConfigImpl(MachineConfig machine) {
- this(machine.getInstallers(), machine.getServers(), machine.getEnv(), machine.getAttributes());
+ this(
+ machine.getInstallers(),
+ machine.getServers(),
+ machine.getEnv(),
+ machine.getAttributes(),
+ machine.getVolumes());
}
@Override
@@ -86,6 +102,14 @@ public class MachineConfigImpl implements MachineConfig {
return attributes;
}
+ @Override
+ public Map getVolumes() {
+ if (volumes == null) {
+ volumes = new HashMap<>();
+ }
+ return volumes;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -98,7 +122,8 @@ public class MachineConfigImpl implements MachineConfig {
return getInstallers().equals(that.getInstallers())
&& getEnv().equals(that.getEnv())
&& getAttributes().equals(that.getAttributes())
- && getServers().equals(that.getServers());
+ && getServers().equals(that.getServers())
+ && getVolumes().equals(that.getVolumes());
}
@Override
@@ -108,6 +133,7 @@ public class MachineConfigImpl implements MachineConfig {
hash = 31 * hash + getEnv().hashCode();
hash = 31 * hash + getAttributes().hashCode();
hash = 31 * hash + getServers().hashCode();
+ hash = 31 * hash + getVolumes().hashCode();
return hash;
}
@@ -122,6 +148,8 @@ public class MachineConfigImpl implements MachineConfig {
+ attributes
+ ", servers="
+ servers
+ + ", volumes="
+ + volumes
+ '}';
}
}
diff --git a/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/VolumeImpl.java b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/VolumeImpl.java
new file mode 100644
index 0000000000..833055ba0f
--- /dev/null
+++ b/ide/che-core-ide-api/src/main/java/org/eclipse/che/ide/api/workspace/model/VolumeImpl.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2012-2017 Red Hat, Inc.
+ * 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:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.ide.api.workspace.model;
+
+import java.util.Objects;
+import org.eclipse.che.api.core.model.workspace.config.Volume;
+
+/** @author Alexander Garagatyi */
+public class VolumeImpl implements Volume {
+ private final String path;
+
+ public VolumeImpl(String path) {
+ this.path = path;
+ }
+
+ public VolumeImpl(Volume value) {
+ path = value.getPath();
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof VolumeImpl)) {
+ return false;
+ }
+ final VolumeImpl that = (VolumeImpl) obj;
+ return Objects.equals(path, that.path);
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 7;
+ hash = 31 * hash + Objects.hashCode(path);
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return "VolumeImpl{" + "path='" + path + '\'' + '}';
+ }
+}
diff --git a/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/resources/META-INF/persistence.xml b/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/resources/META-INF/persistence.xml
index 6b20e5a992..3e7b06c196 100644
--- a/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/resources/META-INF/persistence.xml
+++ b/multiuser/integration-tests/che-multiuser-cascade-removal/src/test/resources/META-INF/persistence.xml
@@ -29,6 +29,7 @@
org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute
org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl
org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl
+ org.eclipse.che.api.workspace.server.model.impl.VolumeImpl
org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl
org.eclipse.che.api.workspace.server.model.impl.CommandImpl
diff --git a/multiuser/integration-tests/che-multiuser-postgresql-tck/src/test/resources/META-INF/persistence.xml b/multiuser/integration-tests/che-multiuser-postgresql-tck/src/test/resources/META-INF/persistence.xml
index f9f8f38c0d..e6387da621 100644
--- a/multiuser/integration-tests/che-multiuser-postgresql-tck/src/test/resources/META-INF/persistence.xml
+++ b/multiuser/integration-tests/che-multiuser-postgresql-tck/src/test/resources/META-INF/persistence.xml
@@ -30,6 +30,7 @@
org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl
org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl
org.eclipse.che.api.workspace.server.model.impl.stack.StackImpl
+ org.eclipse.che.api.workspace.server.model.impl.VolumeImpl
org.eclipse.che.api.workspace.server.model.impl.CommandImpl
org.eclipse.che.workspace.infrastructure.docker.snapshot.MachineSourceImpl
diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/WorkspaceTckModule.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/WorkspaceTckModule.java
index c771e8f0c2..aee87ba352 100644
--- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/WorkspaceTckModule.java
+++ b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/jpa/WorkspaceTckModule.java
@@ -23,6 +23,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
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.stack.StackImpl;
@@ -75,7 +76,8 @@ public class WorkspaceTckModule extends TckModule {
ServerConfigImpl.class,
StackImpl.class,
CommandImpl.class,
- RecipeImpl.class)
+ RecipeImpl.class,
+ VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.setExceptionHandler(H2ExceptionHandler.class)
diff --git a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/JpaTckModule.java b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/JpaTckModule.java
index ace4264ffe..7018583d9e 100644
--- a/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/JpaTckModule.java
+++ b/multiuser/permission/che-multiuser-permission-workspace/src/test/java/org/eclipse/che/multiuser/permission/workspace/server/spi/jpa/JpaTckModule.java
@@ -20,6 +20,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
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.stack.StackImpl;
@@ -67,7 +68,8 @@ public class JpaTckModule extends TckModule {
ServerConfigImpl.class,
StackImpl.class,
CommandImpl.class,
- RecipeImpl.class)
+ RecipeImpl.class,
+ VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.setExceptionHandler(H2ExceptionHandler.class)
diff --git a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryTckModule.java b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryTckModule.java
index 87a44314af..6d4c87263a 100644
--- a/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryTckModule.java
+++ b/wsmaster/che-core-api-factory/src/test/java/org/eclipse/che/api/factory/server/jpa/FactoryTckModule.java
@@ -29,6 +29,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
import org.eclipse.che.api.workspace.server.model.impl.WorkspaceConfigImpl;
import org.eclipse.che.commons.test.db.H2DBTestServer;
import org.eclipse.che.commons.test.db.H2JpaCleaner;
@@ -75,7 +76,8 @@ public class FactoryTckModule extends TckModule {
MachineConfigImpl.class,
SourceStorageImpl.class,
ServerConfigImpl.class,
- CommandImpl.class)
+ CommandImpl.class,
+ VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.setExceptionHandler(H2ExceptionHandler.class)
diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/MachineConfigDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/MachineConfigDto.java
index d34ce3cc82..74b71a0dcc 100644
--- a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/MachineConfigDto.java
+++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/MachineConfigDto.java
@@ -52,4 +52,12 @@ public interface MachineConfigDto extends MachineConfig {
void setAttributes(Map attributes);
MachineConfigDto withAttributes(Map attributes);
+
+ @Override
+ @FactoryParameter(obligation = OPTIONAL)
+ Map getVolumes();
+
+ void setVolumes(Map volumes);
+
+ MachineConfigDto withVolumes(Map volumes);
}
diff --git a/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/VolumeDto.java b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/VolumeDto.java
new file mode 100644
index 0000000000..8837aafc6b
--- /dev/null
+++ b/wsmaster/che-core-api-workspace-shared/src/main/java/org/eclipse/che/api/workspace/shared/dto/VolumeDto.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012-2017 Red Hat, Inc.
+ * 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:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.workspace.shared.dto;
+
+import org.eclipse.che.api.core.model.workspace.config.Volume;
+import org.eclipse.che.dto.shared.DTO;
+
+/** @author Alexander Garagatyi */
+@DTO
+public interface VolumeDto extends Volume {
+ @Override
+ String getPath();
+
+ void setPath(String path);
+
+ VolumeDto withPath(String path);
+}
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java
index 1dea864a5a..26eb6ecbb9 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/DtoConverter.java
@@ -26,6 +26,7 @@ import org.eclipse.che.api.core.model.workspace.config.MachineConfig;
import org.eclipse.che.api.core.model.workspace.config.ProjectConfig;
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
import org.eclipse.che.api.core.model.workspace.config.SourceStorage;
+import org.eclipse.che.api.core.model.workspace.config.Volume;
import org.eclipse.che.api.core.model.workspace.runtime.Machine;
import org.eclipse.che.api.core.model.workspace.runtime.RuntimeIdentity;
import org.eclipse.che.api.core.model.workspace.runtime.Server;
@@ -41,6 +42,7 @@ import org.eclipse.che.api.workspace.shared.dto.RuntimeIdentityDto;
import org.eclipse.che.api.workspace.shared.dto.ServerConfigDto;
import org.eclipse.che.api.workspace.shared.dto.ServerDto;
import org.eclipse.che.api.workspace.shared.dto.SourceStorageDto;
+import org.eclipse.che.api.workspace.shared.dto.VolumeDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceDto;
import org.eclipse.che.api.workspace.shared.dto.stack.StackComponentDto;
@@ -204,6 +206,14 @@ public final class DtoConverter {
if (machine.getAttributes() != null) {
machineDto.setAttributes(machine.getAttributes());
}
+ if (machine.getVolumes() != null) {
+ machineDto.setVolumes(
+ machine
+ .getVolumes()
+ .entrySet()
+ .stream()
+ .collect(toMap(Map.Entry::getKey, entry -> asDto(entry.getValue()))));
+ }
return machineDto;
}
@@ -254,5 +264,10 @@ public final class DtoConverter {
.withOwner(identity.getOwner());
}
+ /** Converts {@link Volume} to {@link VolumeDto}. */
+ public static VolumeDto asDto(Volume volume) {
+ return newDto(VolumeDto.class).withPath(volume.getPath());
+ }
+
private DtoConverter() {}
}
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java
index a645e25d84..294f8f93b5 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/WorkspaceValidator.java
@@ -28,6 +28,7 @@ import org.eclipse.che.api.core.model.workspace.config.Command;
import org.eclipse.che.api.core.model.workspace.config.Environment;
import org.eclipse.che.api.core.model.workspace.config.MachineConfig;
import org.eclipse.che.api.core.model.workspace.config.Recipe;
+import org.eclipse.che.api.core.model.workspace.config.Volume;
import org.eclipse.che.api.workspace.server.spi.InfrastructureException;
/**
@@ -45,6 +46,9 @@ public class WorkspaceValidator {
private static final Pattern WS_NAME =
Pattern.compile("[a-zA-Z0-9][-_.a-zA-Z0-9]{1,98}[a-zA-Z0-9]");
+ private static final Pattern VOLUME_NAME = Pattern.compile("[a-z][a-z0-9]{1,18}");
+ private static final Pattern VOLUME_PATH = Pattern.compile("/.+");
+
private final WorkspaceRuntimes runtimes;
@Inject
@@ -146,6 +150,27 @@ public class WorkspaceValidator {
memoryAttribute, MEMORY_LIMIT_ATTRIBUTE, name));
}
}
+
+ for (Entry volumeEntry : machine.getVolumes().entrySet()) {
+ String volumeName = volumeEntry.getKey();
+ check(
+ VOLUME_NAME.matcher(volumeName).matches(),
+ "Volume name '%s' in machine '%s' is invalid",
+ volumeName,
+ name);
+ Volume volume = volumeEntry.getValue();
+ check(
+ volume != null && !isNullOrEmpty(volume.getPath()),
+ "Path of volume '%s' in machine '%s' is invalid. It should not be empty",
+ volumeName,
+ name);
+ check(
+ VOLUME_PATH.matcher(volume.getPath()).matches(),
+ "Path '%s' of volume '%s' in machine '%s' is invalid. It should be absolute",
+ volume.getPath(),
+ volumeName,
+ name);
+ }
}
/**
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/MachineConfigImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/MachineConfigImpl.java
index 0d978a2b07..258fd5fc6e 100644
--- a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/MachineConfigImpl.java
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/MachineConfigImpl.java
@@ -30,6 +30,7 @@ import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.che.api.core.model.workspace.config.MachineConfig;
import org.eclipse.che.api.core.model.workspace.config.ServerConfig;
+import org.eclipse.che.api.core.model.workspace.config.Volume;
/** @author Alexander Garagatyi */
@Entity(name = "ExternalMachine")
@@ -72,13 +73,19 @@ public class MachineConfigImpl implements MachineConfig {
@MapKeyColumn(name = "servers_key")
private Map servers;
+ @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
+ @JoinColumn(name = "machine_id")
+ @MapKeyColumn(name = "name")
+ private Map volumes;
+
public MachineConfigImpl() {}
public MachineConfigImpl(
List installers,
Map servers,
Map env,
- Map attributes) {
+ Map attributes,
+ Map volumes) {
if (installers != null) {
this.installers = new ArrayList<>(installers);
}
@@ -97,10 +104,23 @@ public class MachineConfigImpl implements MachineConfig {
if (attributes != null) {
this.attributes = new HashMap<>(attributes);
}
+ if (volumes != null) {
+ this.volumes =
+ volumes
+ .entrySet()
+ .stream()
+ .collect(
+ Collectors.toMap(Map.Entry::getKey, entry -> new VolumeImpl(entry.getValue())));
+ }
}
public MachineConfigImpl(MachineConfig machine) {
- this(machine.getInstallers(), machine.getServers(), machine.getEnv(), machine.getAttributes());
+ this(
+ machine.getInstallers(),
+ machine.getServers(),
+ machine.getEnv(),
+ machine.getAttributes(),
+ machine.getVolumes());
}
@Override
@@ -171,6 +191,23 @@ public class MachineConfigImpl implements MachineConfig {
return this;
}
+ @Override
+ public Map getVolumes() {
+ if (volumes == null) {
+ volumes = new HashMap<>();
+ }
+ return volumes;
+ }
+
+ public void setVolumes(Map volumes) {
+ this.volumes = volumes;
+ }
+
+ public MachineConfigImpl withVolumes(Map volumes) {
+ this.volumes = volumes;
+ return this;
+ }
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
@@ -184,7 +221,8 @@ public class MachineConfigImpl implements MachineConfig {
&& getInstallers().equals(that.getInstallers())
&& getEnv().equals(that.getEnv())
&& getAttributes().equals(that.getAttributes())
- && getServers().equals(that.getServers());
+ && getServers().equals(that.getServers())
+ && getVolumes().equals(that.getVolumes());
}
@Override
@@ -195,6 +233,7 @@ public class MachineConfigImpl implements MachineConfig {
hash = 31 * hash + getEnv().hashCode();
hash = 31 * hash + getAttributes().hashCode();
hash = 31 * hash + getServers().hashCode();
+ hash = 31 * hash + getVolumes().hashCode();
return hash;
}
@@ -211,6 +250,8 @@ public class MachineConfigImpl implements MachineConfig {
+ attributes
+ ", servers="
+ servers
+ + ", volumes="
+ + volumes
+ '}';
}
}
diff --git a/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/VolumeImpl.java b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/VolumeImpl.java
new file mode 100644
index 0000000000..77018c5f49
--- /dev/null
+++ b/wsmaster/che-core-api-workspace/src/main/java/org/eclipse/che/api/workspace/server/model/impl/VolumeImpl.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2012-2017 Red Hat, Inc.
+ * 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:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.workspace.server.model.impl;
+
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import org.eclipse.che.api.core.model.workspace.config.Volume;
+
+/** @author Alexander Garagatyi */
+@Entity(name = "MachineVolume")
+@Table(name = "machine_volume")
+public class VolumeImpl implements Volume {
+
+ @Id
+ @GeneratedValue
+ @Column(name = "id")
+ private Long id;
+
+ @Column(name = "path")
+ private String path;
+
+ public VolumeImpl() {}
+
+ public VolumeImpl(Volume value) {
+ path = value.getPath();
+ }
+
+ @Override
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public VolumeImpl withPath(String path) {
+ this.path = path;
+ return this;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof VolumeImpl)) {
+ return false;
+ }
+ VolumeImpl volume = (VolumeImpl) o;
+ return Objects.equals(id, volume.id) && Objects.equals(getPath(), volume.getPath());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(id, getPath());
+ }
+
+ @Override
+ public String toString() {
+ return "VolumeImpl{" + "id=" + id + ", path='" + path + '\'' + '}';
+ }
+}
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 216eaf26ee..b0e350ba65 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
@@ -558,7 +558,8 @@ public class WorkspaceManagerTest {
singletonList("org.eclipse.che.ws-agent"),
null,
singletonMap("CHE_ENV", "value"),
- singletonMap(MEMORY_LIMIT_ATTRIBUTE, "10000"));
+ singletonMap(MEMORY_LIMIT_ATTRIBUTE, "10000"),
+ emptyMap());
EnvironmentImpl environment =
new EnvironmentImpl(
new RecipeImpl("type", "contentType", "content", null),
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 fde6280225..44fffb91bd 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
@@ -915,7 +915,8 @@ public class WorkspaceServiceTest {
singletonList("org.eclipse.che.ws-agent"),
null,
singletonMap("CHE_ENV", "value"),
- singletonMap(MEMORY_LIMIT_ATTRIBUTE, "10000"));
+ singletonMap(MEMORY_LIMIT_ATTRIBUTE, "10000"),
+ emptyMap());
return DtoConverter.asDto(
new EnvironmentImpl(
diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java
index e29f0722c3..1b178cb806 100644
--- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java
+++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/WorkspaceValidatorTest.java
@@ -27,6 +27,7 @@ import org.eclipse.che.api.workspace.shared.dto.EnvironmentDto;
import org.eclipse.che.api.workspace.shared.dto.MachineConfigDto;
import org.eclipse.che.api.workspace.shared.dto.RecipeDto;
import org.eclipse.che.api.workspace.shared.dto.ServerConfigDto;
+import org.eclipse.che.api.workspace.shared.dto.VolumeDto;
import org.eclipse.che.api.workspace.shared.dto.WorkspaceConfigDto;
import org.mockito.InjectMocks;
import org.mockito.Mock;
@@ -242,6 +243,89 @@ public class WorkspaceValidatorTest {
wsValidator.validateConfig(config);
}
+ @Test(
+ expectedExceptions = ValidationException.class,
+ expectedExceptionsMessageRegExp = "Volume name '.*' in machine '.*' is invalid",
+ dataProvider = "illegalVolumeNameProvider"
+ )
+ public void shouldFailValidationIfVolumeNameDoesNotMatchCriteria(String volumeName)
+ throws Exception {
+ final WorkspaceConfigDto config = createConfig();
+ EnvironmentDto env = config.getEnvironments().values().iterator().next();
+ MachineConfigDto machine = env.getMachines().values().iterator().next();
+ machine.getVolumes().put(volumeName, newDto(VolumeDto.class).withPath("/path"));
+
+ wsValidator.validateConfig(config);
+ }
+
+ @DataProvider(name = "illegalVolumeNameProvider")
+ public static Object[][] illegalVolumeNameProvider() {
+ return new Object[][] {
+ {"0volume"},
+ {"CAPITAL"},
+ {"veryveryveryveryveryveryverylongname"},
+ {"volume/name"},
+ {"volume_name"},
+ {"volume-name"}
+ };
+ }
+
+ @Test(
+ expectedExceptions = ValidationException.class,
+ expectedExceptionsMessageRegExp =
+ "Path of volume '.*' in machine '.*' is invalid. It should not be empty"
+ )
+ public void shouldFailValidationIfVolumeValueIsEmpty() throws Exception {
+ final WorkspaceConfigDto config = createConfig();
+ EnvironmentDto env = config.getEnvironments().values().iterator().next();
+ MachineConfigDto machine = env.getMachines().values().iterator().next();
+ machine.getVolumes().put("volume1", null);
+
+ wsValidator.validateConfig(config);
+ }
+
+ @Test(
+ expectedExceptions = ValidationException.class,
+ expectedExceptionsMessageRegExp =
+ "Path of volume '.*' in machine '.*' is invalid. It should not be empty"
+ )
+ public void shouldFailValidationIfVolumePathIsEmpty() throws Exception {
+ final WorkspaceConfigDto config = createConfig();
+ EnvironmentDto env = config.getEnvironments().values().iterator().next();
+ MachineConfigDto machine = env.getMachines().values().iterator().next();
+ machine.getVolumes().put("volume1", newDto(VolumeDto.class).withPath(""));
+
+ wsValidator.validateConfig(config);
+ }
+
+ @Test(
+ expectedExceptions = ValidationException.class,
+ expectedExceptionsMessageRegExp =
+ "Path of volume '.*' in machine '.*' is invalid. It should not be empty"
+ )
+ public void shouldFailValidationIfVolumePathIsNull() throws Exception {
+ final WorkspaceConfigDto config = createConfig();
+ EnvironmentDto env = config.getEnvironments().values().iterator().next();
+ MachineConfigDto machine = env.getMachines().values().iterator().next();
+ machine.getVolumes().put("volume1", newDto(VolumeDto.class).withPath(null));
+
+ wsValidator.validateConfig(config);
+ }
+
+ @Test(
+ expectedExceptions = ValidationException.class,
+ expectedExceptionsMessageRegExp =
+ "Path '.*' of volume '.*' in machine '.*' is invalid. It should be absolute"
+ )
+ public void shouldFailValidationIfVolumePathIsNotAbsolute() throws Exception {
+ final WorkspaceConfigDto config = createConfig();
+ EnvironmentDto env = config.getEnvironments().values().iterator().next();
+ MachineConfigDto machine = env.getMachines().values().iterator().next();
+ machine.getVolumes().put("volume1", newDto(VolumeDto.class).withPath("not/absolute/path"));
+
+ wsValidator.validateConfig(config);
+ }
+
private static WorkspaceConfigDto createConfig() {
final WorkspaceConfigDto workspaceConfigDto =
newDto(WorkspaceConfigDto.class).withName("ws-name").withDefaultEnv("dev-env");
diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java
index 01e6f7528c..509162f5ff 100644
--- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java
+++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/jpa/WorkspaceTckModule.java
@@ -20,6 +20,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
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.stack.StackImpl;
@@ -61,7 +62,8 @@ public class WorkspaceTckModule extends TckModule {
ServerConfigImpl.class,
StackImpl.class,
CommandImpl.class,
- RecipeImpl.class)
+ RecipeImpl.class,
+ VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.setExceptionHandler(H2ExceptionHandler.class)
diff --git a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java
index 2dc709f182..6763ca310c 100644
--- a/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java
+++ b/wsmaster/che-core-api-workspace/src/test/java/org/eclipse/che/api/workspace/server/spi/tck/WorkspaceDaoTest.java
@@ -46,6 +46,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
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.spi.WorkspaceDao;
@@ -554,6 +555,12 @@ public class WorkspaceDaoTest {
exMachine1.setInstallers(ImmutableList.of("agent5", "agent4"));
exMachine1.setAttributes(singletonMap("att1", "val"));
exMachine1.setEnv(ImmutableMap.of("CHE_ENV1", "value", "CHE_ENV2", "value"));
+ exMachine1.setVolumes(
+ ImmutableMap.of(
+ "vol1",
+ new VolumeImpl().withPath("/path/1"),
+ "vol2",
+ new VolumeImpl().withPath("/path/2")));
final MachineConfigImpl exMachine2 = new MachineConfigImpl();
final ServerConfigImpl serverConf3 = new ServerConfigImpl("2333", "https", "path3");
@@ -562,6 +569,7 @@ public class WorkspaceDaoTest {
exMachine2.setInstallers(ImmutableList.of("agent2", "agent1"));
exMachine2.setAttributes(singletonMap("att1", "val"));
exMachine2.setEnv(singletonMap("CHE_ENV2", "value"));
+ exMachine2.setVolumes(ImmutableMap.of("vol2", new VolumeImpl().withPath("/path/2")));
final MachineConfigImpl exMachine3 = new MachineConfigImpl();
final ServerConfigImpl serverConf5 = new ServerConfigImpl("2333", "https", "path5");
@@ -569,6 +577,7 @@ public class WorkspaceDaoTest {
exMachine3.setInstallers(ImmutableList.of("agent6", "agent2"));
exMachine3.setAttributes(singletonMap("att1", "val"));
exMachine3.setEnv(singletonMap("CHE_ENV3", "value"));
+ exMachine3.setVolumes(ImmutableMap.of("vol3", new VolumeImpl().withPath("/path/3")));
// Environments
final RecipeImpl recipe1 = new RecipeImpl();
diff --git a/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.0.0/7__add_machine_volumes.sql b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.0.0/7__add_machine_volumes.sql
new file mode 100644
index 0000000000..7d3ddf39f8
--- /dev/null
+++ b/wsmaster/che-core-sql-schema/src/main/resources/che-schema/6.0.0/7__add_machine_volumes.sql
@@ -0,0 +1,25 @@
+--
+-- Copyright (c) 2012-2017 Red Hat, Inc.
+-- 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:
+-- Red Hat, Inc. - initial API and implementation
+--
+
+-- Machine volumes configuration -----------------------------------------------
+CREATE TABLE machine_volume (
+ id BIGINT NOT NULL,
+ name VARCHAR(255),
+ path VARCHAR(255) NOT NULL,
+ machine_id BIGINT,
+
+ PRIMARY KEY (id)
+);
+--constraints
+ALTER TABLE machine_volume ADD CONSTRAINT fk_machine_volume_id FOREIGN KEY (machine_id) REFERENCES externalmachine (id);
+--------------------------------------------------------------------------------
+--indexes
+CREATE INDEX index_machine_volume_machine_id ON machine_volume (machine_id);
diff --git a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java
index 53ebcad7a2..8d46c01ed0 100644
--- a/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java
+++ b/wsmaster/integration-tests/cascade-removal/src/test/java/org/eclipse/che/core/db/jpa/CascadeRemovalTest.java
@@ -71,6 +71,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
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.stack.StackImpl;
@@ -160,7 +161,8 @@ public class CascadeRemovalTest {
StackImpl.class,
CommandImpl.class,
RecipeImpl.class,
- SshPairImpl.class)
+ SshPairImpl.class,
+ VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.setExceptionHandler(H2ExceptionHandler.class)
diff --git a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java
index 94dba7778e..6f9caac38a 100644
--- a/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java
+++ b/wsmaster/integration-tests/postgresql-tck/src/test/java/PostgreSqlTckModule.java
@@ -50,6 +50,7 @@ import org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.RecipeImpl;
import org.eclipse.che.api.workspace.server.model.impl.ServerConfigImpl;
import org.eclipse.che.api.workspace.server.model.impl.SourceStorageImpl;
+import org.eclipse.che.api.workspace.server.model.impl.VolumeImpl;
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.stack.StackImpl;
@@ -116,7 +117,8 @@ public class PostgreSqlTckModule extends TckModule {
CommandImpl.class,
SshPairImpl.class,
InstallerImpl.class,
- InstallerServerConfigImpl.class)
+ InstallerServerConfigImpl.class,
+ VolumeImpl.class)
.addEntityClass(
"org.eclipse.che.api.workspace.server.model.impl.ProjectConfigImpl$Attribute")
.build());