Skip to content

Commit

Permalink
Allow getting workspace storage path inside of Che master container
Browse files Browse the repository at this point in the history
Signed-off-by: Oleksandr Garagatyi <ogaragat@redhat.com>
  • Loading branch information
Oleksandr Garagatyi committed Dec 19, 2017
1 parent ccee5b0 commit 632e28f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 114 deletions.
3 changes: 1 addition & 2 deletions dockerfiles/che/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,6 @@ init() {
sudo chown -R ${CHE_USER} ${CHE_LOGS_DIR}
fi


export CHE_WORKSPACE_STORAGE=/data/workspaces
export CHE_DATABASE=/data/storage
export CHE_TEMPLATE_STORAGE=/data/templates
export CHE_WORKSPACE_AGENT_DEV=${CHE_DATA_HOST}/lib/ws-agent.tar.gz
Expand All @@ -246,6 +244,7 @@ init() {
export CHE_DOCKER_IP_EXTERNAL=${HOSTNAME}
fi
### Necessary to allow the container to write projects to the folder
export CHE_WORKSPACE_STORAGE__MASTER__PATH=/data/workspaces
export CHE_WORKSPACE_STORAGE="${CHE_DATA_HOST}/workspaces"
export CHE_WORKSPACE_STORAGE_CREATE_FOLDERS=false

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,8 @@
import org.eclipse.che.api.core.model.workspace.Workspace;
import org.eclipse.che.api.core.util.SystemInfo;
import org.eclipse.che.api.workspace.server.spi.WorkspaceDao;
import org.eclipse.che.commons.annotation.Nullable;
import org.eclipse.che.workspace.infrastructure.docker.WindowsHostUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Provides path to workspace projects folder on host.
Expand All @@ -39,96 +38,119 @@
@Singleton
public class LocalProjectsFolderPathProvider {

public static final String ALLOW_FOLDERS_CREATION_ENV_VARIABLE =
"CHE_WORKSPACE_STORAGE_CREATE_FOLDERS";
public static final String WORKSPACE_STORAGE_PATH_ENV_VARIABLE = "CHE_WORKSPACE_STORAGE";
public static final String WORKSPACE_STORAGE_MIGRATION_FLAG_ENV_VARIABLE =
static final String ALLOW_FOLDERS_CREATION_PROPERTY = "che.workspace.storage.create.folders";
static final String WORKSPACE_STORAGE_MIGRATION_FLAG_PROPERTY =
"che.workspace.migrate_workspaces_stored_by_name";
static final String WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY = "che.workspace.storage";
static final String CHE_MASTER_SPECIFIC_WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY =
"che.workspace.storage_master_path";
static final String SINGLE_MOUNTPOINT_FOR_ALL_WORKSPACES_PROPERTY = "host.projects.root";

private static final Logger LOG = LoggerFactory.getLogger(LocalProjectsFolderPathProvider.class);

private final WorkspaceDao workspaceDao;
private final boolean isWindows;
private final boolean migrationOnStartup;
private final LocalProjectsMigrator localProjectsMigrator;
private final WorkspaceDao workspaceDao;

/**
* Value provide path to directory on host machine where will by all created and mount to the
* created workspaces folder that become root of workspace inside machine. Inside machine it will
* point to the directory described by {@literal che.workspace.projects.storage}.
*
* <p>For example: if you set {@literal che.workspaces.storage} to the /home/user/che/workspaces
* after creating new workspace will be created new folder
* /home/user/che/workspaces/{workspaceName} and it will be mount to the dev-machine to {@literal
* after creating new workspace will be created new folder /home/user/che/workspaces/{workspaceId}
* and it will be mount to the machine with projects volume to {@literal
* che.workspace.projects.storage}
*/
private String workspacesMountPoint;
private final String workspacesMountPoint;

/**
* this value provide path to projects on local host if this value will be set all workspace will
* This value provide path to projects on local host if this value will be set all workspace will
* manage same projects from your host
*/
@Inject(optional = true)
@Named("host.projects.root")
private String hostProjectsFolder;
@Named(SINGLE_MOUNTPOINT_FOR_ALL_WORKSPACES_PROPERTY)
private String singleMountPointForAllWorkspaces;

/**
* If environment variable with name {@link #ALLOW_FOLDERS_CREATION_ENV_VARIABLE} is equal
* (ignoring case) to {@literal false} then this field is set to false. Otherwise it is set to
* true. It is also possible to overwrite with named constant.
*/
@Inject(optional = true)
@Named("che.workspace.storage.create_folders")
private boolean createFolders = true;
@Named(CHE_MASTER_SPECIFIC_WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY)
private String workspacesMountPointForCheMaster;

@Inject(optional = true)
@Named("che.user.workspaces.storage")
private String oldWorkspacesMountPoint;
@Named(ALLOW_FOLDERS_CREATION_PROPERTY)
private boolean createFolders = true;

@Inject
public LocalProjectsFolderPathProvider(
@Named("che.workspace.storage") String workspacesMountPoint,
@Named("che.workspace.migrate_workspace_projects_on_startup") boolean migrationOnStartup,
@Named(WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY) String workspacesMountPoint,
@Named(WORKSPACE_STORAGE_MIGRATION_FLAG_PROPERTY) boolean migrationOnStartup,
WorkspaceDao workspaceDao,
LocalProjectsMigrator localProjectsMigrator)
throws IOException {
this.workspacesMountPoint = workspacesMountPoint;
this.migrationOnStartup = migrationOnStartup;
this.workspaceDao = workspaceDao;
this.isWindows = SystemInfo.isWindows();
this.localProjectsMigrator = localProjectsMigrator;
this(
workspacesMountPoint,
null,
migrationOnStartup,
null,
null,
workspaceDao,
localProjectsMigrator,
SystemInfo.isWindows());
}

@VisibleForTesting
protected LocalProjectsFolderPathProvider(
String workspacesMountPoint,
String oldWorkspacesMountPoint,
@Nullable String workspacesMountPointForCheMaster,
boolean migrationOnStartup,
String projectsFolder,
boolean createFolders,
@Nullable String singleMountPointForAllWorkspaces,
@Nullable Boolean createFolders,
WorkspaceDao workspaceDao,
LocalProjectsMigrator localProjectsMigrator,
boolean isWindows)
throws IOException {
this.workspaceDao = workspaceDao;
this.workspacesMountPoint = workspacesMountPoint;
this.migrationOnStartup = migrationOnStartup;
this.hostProjectsFolder = projectsFolder;
this.createFolders = createFolders;
this.oldWorkspacesMountPoint = oldWorkspacesMountPoint;
this.localProjectsMigrator = localProjectsMigrator;
this.isWindows = isWindows;
this.localProjectsMigrator = localProjectsMigrator;

if (createFolders != null) {
this.createFolders = createFolders;
}
if (singleMountPointForAllWorkspaces != null) {
this.singleMountPointForAllWorkspaces = singleMountPointForAllWorkspaces;
}
// In case workspace mount path specific for che master is not defined we treat it equal to
// regular workspace mount point
if (workspacesMountPointForCheMaster != null) {
this.workspacesMountPointForCheMaster = workspacesMountPointForCheMaster;
} else {
this.workspacesMountPointForCheMaster = workspacesMountPoint;
}
// Priority of workspace storage path sources:
// If Che is running on Windows
// che-home-location/vfs
// Otherwise
// use value from property injected into constructor
// find root directory for projects in workspaces
if (isWindows) {
final Path vfs = WindowsHostUtils.getCheHome().resolve("vfs");
this.workspacesMountPoint = vfs.toString();
} else {
this.workspacesMountPoint = workspacesMountPoint;
}
}

public String getPath(String workspaceId) throws IOException {
if (!isWindows && hostProjectsFolder != null) {
return hostProjectsFolder;
if (!isWindows && singleMountPointForAllWorkspaces != null) {
return singleMountPointForAllWorkspaces;
}
return doGetPathById(workspaceId);
}

public String getPathByName(String workspaceName, String workspaceNamespace) throws IOException {
if (!isWindows && hostProjectsFolder != null) {
return hostProjectsFolder;
@Deprecated
String getPathByName(String workspaceName, String workspaceNamespace) throws IOException {
if (!isWindows && singleMountPointForAllWorkspaces != null) {
return singleMountPointForAllWorkspaces;
}

try {
Expand All @@ -141,58 +163,35 @@ public String getPathByName(String workspaceName, String workspaceNamespace) thr

private String doGetPathById(String workspaceId) throws IOException {

final String workspaceFolderPath =
Paths.get(workspacesMountPoint).resolve(workspaceId).toString();
ensureExist(workspaceFolderPath, null);
String workspaceFolderPath = Paths.get(workspacesMountPoint).resolve(workspaceId).toString();
// Since Che may be running inside of container and workspaces are mounted not in the same way
// they will be mounted from host to workspace's containers we use Che master specific paths.
// In cases when Che master specific path is not defined it will be equal to the workspace's
// containers one.
String workspaceFolderPathForCheMaster =
Paths.get(workspacesMountPointForCheMaster).resolve(workspaceId).toString();
ensureExist(workspaceFolderPathForCheMaster, null);
return workspaceFolderPath;
}

@VisibleForTesting
@PostConstruct
void init() throws IOException {
// check folders creation flag from environment variable
String allowFoldersCreationEnvVar = System.getenv(ALLOW_FOLDERS_CREATION_ENV_VARIABLE);
if ("false".equalsIgnoreCase(allowFoldersCreationEnvVar)) {
createFolders = false;
}

// Priority of workspace storage path sources:
// If Che is running on Windows
// che-home-location/vfs
// Otherwise
// If environment variable for storage location is set
// use value of that variable
// Otherwise
// If old property of workspace storage is set
// use value of that property for backward compatibility
// Otherwise
// use up-to-date property
// find root directory for projects in workspaces
if (isWindows) {
final Path vfs = WindowsHostUtils.getCheHome().resolve("vfs");
workspacesMountPoint = vfs.toString();
} else {
String workspaceStorageFromEnv = System.getenv(WORKSPACE_STORAGE_PATH_ENV_VARIABLE);
if (workspaceStorageFromEnv != null) {
workspacesMountPoint = workspaceStorageFromEnv;
} else if (oldWorkspacesMountPoint != null) {
workspacesMountPoint = oldWorkspacesMountPoint;
}
}

// create directories if needed
if (hostProjectsFolder == null) {
ensureExist(
workspacesMountPoint,
oldWorkspacesMountPoint == null
? "che.workspace.storage"
: "che.user.workspaces.storage");
if (singleMountPointForAllWorkspaces != null) {
ensureExist(singleMountPointForAllWorkspaces, SINGLE_MOUNTPOINT_FOR_ALL_WORKSPACES_PROPERTY);
} else {
ensureExist(hostProjectsFolder, "host.projects.root");
}

if (migrationOnStartup && !isWindows && hostProjectsFolder == null) {
localProjectsMigrator.performMigration(workspacesMountPoint);
ensureExist(workspacesMountPoint, WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY);
ensureExist(
workspacesMountPointForCheMaster,
CHE_MASTER_SPECIFIC_WORKSPACE_PROJECTS_MOUNT_POINT_PROPERTY);

if (migrationOnStartup && !isWindows) {
localProjectsMigrator.performMigration(
workspacesMountPointForCheMaster != null
? workspacesMountPointForCheMaster
: workspacesMountPoint);
}
}
}

Expand Down Expand Up @@ -231,9 +230,4 @@ private void ensureExist(String path, String prop) throws IOException {
}
}
}

/**
* Get all workspaces, and check if they are stored in workspacesMountPoint by their name, and
* migrate them, so they will be stored by id
*/
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,25 +210,6 @@ public void returnsSingleFolderForAllWorkspacesIfConfigured() throws Exception {
assertEquals(providerPath, singleFolderForAllWorkspaces);
}

@Test
public void useOlderFolderIfConfigured() throws Exception {
LocalProjectsFolderPathProvider provider =
new LocalProjectsFolderPathProvider(
workspacesRoot,
oldWorkspacesRoot,
false,
null,
false,
workspaceDao,
localProjectsMigrator,
false);

provider.init();
String providerPath = provider.getPath(WS_ID);

assertEquals(providerPath, Paths.get(oldWorkspacesRoot, WS_ID).toString());
}

@Test(
expectedExceptions = IOException.class,
expectedExceptionsMessageRegExp = "Workspace folder '.*' is not directory"
Expand Down

0 comments on commit 632e28f

Please sign in to comment.