Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CB-5390 use remote file system for storage #2945

Merged
merged 7 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ server/test/io.cloudbeaver.test.platform/workspace/.data/
.classpath
.settings/

## Eclipse PDE
*.product.launch

workspace-dev-ce/
deploy/cloudbeaver
server/**/target
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,29 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.registry.fs.FileSystemProviderRegistry;

import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Path;

/**
* Abstract class that contains methods for loading configuration with gson.
*/
public abstract class BaseServerConfigurationController<T extends WebServerConfiguration>
implements WebServerConfigurationController<T> {
private static final Log log = Log.getLog(BaseServerConfigurationController.class);
@NotNull
private final Path homeDirectory;

private Path workspacePath;

protected BaseServerConfigurationController(@NotNull Path homeDirectory) {
this.homeDirectory = homeDirectory;
}

@NotNull
public Gson getGson() {
Expand All @@ -34,4 +51,51 @@ public Gson getGson() {
protected abstract GsonBuilder getGsonBuilder();

public abstract T getServerConfiguration();


@NotNull
protected synchronized void initWorkspacePath() throws DBException {
if (workspacePath != null) {
log.warn("Workspace directory already initialized: " + workspacePath);
return;
}
String workspaceLocation = getWorkspaceLocation();
URI workspaceUri = URI.create(workspaceLocation);
if (workspaceUri.getScheme() == null) {
// default filesystem
this.workspacePath = getHomeDirectory().resolve(workspaceLocation);
} else {
var externalFsProvider =
FileSystemProviderRegistry.getInstance().getFileSystemProviderBySchema(workspaceUri.getScheme());
if (externalFsProvider == null) {
throw new DBException("File system not found for scheme: " + workspaceUri.getScheme());
}
ClassLoader fsClassloader = externalFsProvider.getInstance().getClass().getClassLoader();
try (FileSystem externalFileSystem = FileSystems.newFileSystem(workspaceUri,
System.getenv(),
fsClassloader);) {
this.workspacePath = externalFileSystem.provider().getPath(workspaceUri);
} catch (Exception e) {
throw new DBException("Failed to initialize workspace path: " + workspaceUri, e);
}
}
log.info("Workspace path initialized: " + workspacePath);
}

@NotNull
protected abstract String getWorkspaceLocation();

@NotNull
protected Path getHomeDirectory() {
return homeDirectory;
}

@NotNull
@Override
public Path getWorkspacePath() {
if (workspacePath == null) {
throw new RuntimeException("Workspace path not initialized");
}
return workspacePath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,12 @@ public String getWorkspaceIdProperty() throws DBException {
return BaseWorkspaceImpl.readWorkspaceIdProperty();
}

@Override
public Path getWorkspaceDirectory() {
return getServerConfigurationController().getWorkspacePath();
}


public String getApplicationId() {
try {
return getApplicationInstanceId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@
return Map.of();
}

@NotNull

Check warning on line 42 in server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfigurationController.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/model/app/WebServerConfigurationController.java#L42

Missing a Javadoc comment.
Path getWorkspacePath();

@NotNull
Gson getGson();
}
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ public String moveResource(
throw new DBException("Resource '" + oldTargetPath + "' doesn't exists");
}
Path newTargetPath = getTargetPath(projectId, normalizedNewResourcePath);
validateResourcePath(newTargetPath.toString());
validateResourcePath(rootPath.relativize(newTargetPath).toString());
if (Files.exists(newTargetPath)) {
throw new DBException("Resource with name %s already exists".formatted(newTargetPath.getFileName()));
}
Expand Down Expand Up @@ -881,7 +881,7 @@ private Path getTargetPath(@NotNull String projectId, @NotNull String resourcePa
if (!targetPath.startsWith(projectPath)) {
throw new DBException("Invalid resource path");
}
return WebAppUtils.getWebApplication().getHomeDirectory().relativize(targetPath);
return targetPath;
} catch (InvalidPathException e) {
throw new DBException("Resource path contains invalid characters");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.UUID;
Expand Down Expand Up @@ -73,18 +74,23 @@ public RMFileLockController(WebApplication application, int maxLockTime) throws
* @return - lock
*/
@NotNull
public RMLock lockProject(@NotNull String projectId,@NotNull String operationName) throws DBException {
public RMLock lockProject(@NotNull String projectId, @NotNull String operationName) throws DBException {
synchronized (RMFileLockController.class) {
try {
createLockFolderIfNeeded();
createProjectFolder(projectId);
Path projectLockFile = getProjectLockFilePath(projectId);

RMLockInfo lockInfo = new RMLockInfo.Builder(projectId, UUID.randomUUID().toString())
.setApplicationId(applicationId)
.setOperationName(operationName)
.setOperationStartTime(System.currentTimeMillis())
.build();
Path projectLockFile = getProjectLockFilePath(projectId);

if (!lockFolderPath.getFileSystem().equals(FileSystems.getDefault())) {
alexander-skoblikov marked this conversation as resolved.
Show resolved Hide resolved
// fake lock for external file system?
return new RMLock(projectLockFile);
}
createLockFolderIfNeeded();
createProjectFolder(projectId);

createLockFile(projectLockFile, lockInfo);
return new RMLock(projectLockFile);
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.cloudbeaver.server;

import io.cloudbeaver.DBWConstants;
import io.cloudbeaver.model.app.WebApplication;
import org.eclipse.core.runtime.Plugin;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.Log;
Expand Down Expand Up @@ -55,7 +56,7 @@
SecurityProviderUtils.registerSecurityProvider();

// Register properties adapter
this.workspace = new WebGlobalWorkspace(this);
this.workspace = new WebGlobalWorkspace(this, (WebApplication) getApplication());
this.workspace.initializeProjects();
QMUtils.initApplication(this);

Expand Down Expand Up @@ -95,14 +96,8 @@
if (tempFolder == null) {
// Make temp folder
monitor.subTask("Create temp folder");
tempFolder = workspace.getAbsolutePath().resolve(DBWConstants.WORK_DATA_FOLDER_NAME);
}
if (!Files.exists(tempFolder)) {
try {
Files.createDirectories(tempFolder);
} catch (IOException e) {
log.error("Can't create temp directory " + tempFolder, e);
}
//we do not use workspace because it can be in external file system
tempFolder = getApplication().getHomeDirectory().resolve(DBWConstants.WORK_DATA_FOLDER_NAME);
alexander-skoblikov marked this conversation as resolved.
Show resolved Hide resolved
}
Path folder = tempFolder.resolve(name);
if (!Files.exists(folder)) {
Expand All @@ -115,6 +110,9 @@
return folder;
}

@NotNull

Check warning on line 113 in server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java

View check run for this annotation

Jenkins-CI-integration / CheckStyle Java Report

server/bundles/io.cloudbeaver.model/src/io/cloudbeaver/server/BaseGQLPlatform.java#L113

Missing a Javadoc comment.
public abstract WebApplication getApplication();

@Override
public synchronized void dispose() {
super.dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.cloudbeaver.server;

import io.cloudbeaver.WebProjectImpl;
import io.cloudbeaver.model.app.WebApplication;
import io.cloudbeaver.utils.WebAppUtils;
import org.eclipse.core.runtime.Platform;
import org.jkiss.code.NotNull;
Expand Down Expand Up @@ -47,18 +48,14 @@ public class WebGlobalWorkspace extends BaseWorkspaceImpl {
protected final Map<String, WebProjectImpl> projects = new LinkedHashMap<>();
private WebGlobalProject globalProject;

public WebGlobalWorkspace(DBPPlatform platform) {
super(platform, Path.of(getWorkspaceURI()));
}
private final WebApplication application;

@NotNull
private static URI getWorkspaceURI() {
String workspacePath = Platform.getInstanceLocation().getURL().toString();
try {
return new URI(workspacePath);
} catch (URISyntaxException e) {
throw new IllegalStateException("Workspace path is invalid: " + workspacePath, e);
}
public WebGlobalWorkspace(
@NotNull DBPPlatform platform,
@NotNull WebApplication application
) {
super(platform, application.getWorkspaceDirectory());
this.application = application;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

import java.io.File;
import java.io.PrintStream;

/**
Expand All @@ -33,7 +32,6 @@ public class WebPlatformActivator extends Plugin {

// The shared instance
private static WebPlatformActivator instance;
private static File configDir;
private PrintStream debugWriter;
private DBPPreferenceStore preferences;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.ModelPreferences;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.auth.AuthInfo;
Expand All @@ -53,19 +54,20 @@
import org.jkiss.dbeaver.runtime.DBWorkbench;
import org.jkiss.dbeaver.runtime.ui.DBPPlatformUI;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.PrefUtils;
import org.jkiss.dbeaver.utils.SystemVariablesResolver;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.StandardConstants;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
Expand Down Expand Up @@ -201,13 +203,20 @@ protected void startServer() {
if (!loadServerConfiguration()) {
return;
}

if (CommonUtils.isEmpty(this.getAppConfiguration().getDefaultUserTeam())) {
throw new DBException("Default user team must be specified");
}
} catch (DBException e) {
log.error(e);
return;
}
// Set default preferences
PrefUtils.setDefaultPreferenceValue(DBWorkbench.getPlatform().getPreferenceStore(),
ModelPreferences.UI_DRIVERS_HOME,
getServerConfiguration().getDriversLocation());
CBPlatform.getInstance().refreshApplicableDrivers();
alexander-skoblikov marked this conversation as resolved.
Show resolved Hide resolved

refreshDisabledDriversConfig();

configurationMode = CommonUtils.isEmpty(getServerConfiguration().getServerName());
Expand Down Expand Up @@ -303,7 +312,7 @@ protected void startServer() {

if (configurationMode) {
// Try to configure automatically
performAutoConfiguration(getMainConfigurationFilePath().toFile().getParentFile());
performAutoConfiguration(getMainConfigurationFilePath().getParent());
} else if (!isMultiNode()) {
var appConfiguration = getServerConfigurationController().getAppConfiguration();
if (appConfiguration.isGrantConnectionsAccessToAnonymousTeam()) {
Expand Down Expand Up @@ -331,7 +340,7 @@ protected void initializeAdditionalConfiguration() {
*
* @param configPath
*/
protected void performAutoConfiguration(File configPath) {
protected void performAutoConfiguration(Path configPath) {
String autoServerName = System.getenv(CBConstants.VAR_AUTO_CB_SERVER_NAME);
String autoServerURL = System.getenv(CBConstants.VAR_AUTO_CB_SERVER_URL);
String autoAdminName = System.getenv(CBConstants.VAR_AUTO_CB_ADMIN_NAME);
Expand All @@ -340,19 +349,19 @@ protected void performAutoConfiguration(File configPath) {
if (CommonUtils.isEmpty(autoServerName) || CommonUtils.isEmpty(autoAdminName) || CommonUtils.isEmpty(
autoAdminPassword)) {
// Try to load from auto config file
if (configPath.exists()) {
File autoConfigFile = new File(configPath, CBConstants.AUTO_CONFIG_FILE_NAME);
if (autoConfigFile.exists()) {
if (Files.exists(configPath)) {
Path autoConfigFile = configPath.resolve(CBConstants.AUTO_CONFIG_FILE_NAME);
if (Files.exists(autoConfigFile)) {
Properties autoProps = new Properties();
try (InputStream is = new FileInputStream(autoConfigFile)) {
try (InputStream is = Files.newInputStream(autoConfigFile)) {
autoProps.load(is);

autoServerName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_SERVER_NAME);
autoServerURL = autoProps.getProperty(CBConstants.VAR_AUTO_CB_SERVER_URL);
autoAdminName = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_NAME);
autoAdminPassword = autoProps.getProperty(CBConstants.VAR_AUTO_CB_ADMIN_PASSWORD);
} catch (IOException e) {
log.error("Error loading auto configuration file '" + autoConfigFile.getAbsolutePath() + "'",
log.error("Error loading auto configuration file '" + autoConfigFile + "'",
e);
}
}
Expand Down Expand Up @@ -439,11 +448,6 @@ public Path getDataDirectory(boolean create) {
return dataDir.toPath();
}

@Override
public Path getWorkspaceDirectory() {
return Path.of(getServerConfiguration().getWorkspaceLocation());
}

private void initializeSecurityController() throws DBException {
securityController = createGlobalSecurityController();
}
Expand Down
Loading