Skip to content

Commit

Permalink
feat(conf): introduce ConfigCheckService to validate config on startup
Browse files Browse the repository at this point in the history
…IQSS#9572

Starting with important local storage locations for the Dataverse application,
this service uses EJB startup mechanisms to verify configuration bits on startup.

Checks for the temp storage location and JSF upload location as crucial parts
of the app, which, if not exist or write protected, while only cause errors and
failures on the first data upload attempt. This is not desirable as it might cause
users to be blocked.
  • Loading branch information
poikilotherm committed Jun 21, 2023
1 parent d71cdf2 commit a4ec3a6
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 18 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package edu.harvard.iq.dataverse.settings;

import edu.harvard.iq.dataverse.util.FileUtil;

import javax.annotation.PostConstruct;
import javax.ejb.DependsOn;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

@Startup
@Singleton
@DependsOn("StartupFlywayMigrator")
public class ConfigCheckService {

private static final Logger logger = Logger.getLogger(ConfigCheckService.class.getCanonicalName());

public static class ConfigurationError extends RuntimeException {
public ConfigurationError(String message) {
super(message);
}
}

@PostConstruct
public void startup() {
if (!checkSystemDirectories()) {
throw new ConfigurationError("Not all configuration checks passed successfully. See logs above.");
}
}

/**
* In this method, we check the existence and write-ability of all important directories we use during
* normal operations. It does not include checks for the storage system. If directories are not available,
* try to create them (and fail when not allowed to).
*
* @return True if all checks successful, false otherwise.
*/
public boolean checkSystemDirectories() {
Map<Path, String> paths = Map.of(
Path.of(JvmSettings.UPLOADS_DIRECTORY.lookup()), "temporary JSF upload space (see " + JvmSettings.UPLOADS_DIRECTORY.getScopedKey() + ")",
Path.of(FileUtil.getFilesTempDirectory()), "temporary processing space (see " + JvmSettings.FILES_DIRECTORY.getScopedKey() + ")");

boolean success = true;
for (Path path : paths.keySet()) {
if (Files.notExists(path)) {
try {
Files.createDirectories(path);
} catch (IOException e) {
logger.log(Level.SEVERE, () -> "Could not create directory " + path + " for " + paths.get(path));
success = false;
}
} else if (!Files.isWritable(path)) {
logger.log(Level.SEVERE, () -> "Directory " + path + " for " + paths.get(path) + " exists, but is not writeable");
success = false;
}
}
return success;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public enum JvmSettings {
// FILES SETTINGS
SCOPE_FILES(PREFIX, "files"),
FILES_DIRECTORY(SCOPE_FILES, "directory"),
UPLOADS_DIRECTORY(SCOPE_FILES, "uploads"),

// SOLR INDEX SETTINGS
SCOPE_SOLR(PREFIX, "solr"),
Expand Down
29 changes: 11 additions & 18 deletions src/main/java/edu/harvard/iq/dataverse/util/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import edu.harvard.iq.dataverse.ingest.IngestServiceShapefileHelper;
import edu.harvard.iq.dataverse.ingest.IngestableDataChecker;
import edu.harvard.iq.dataverse.license.License;
import edu.harvard.iq.dataverse.settings.ConfigCheckService;
import edu.harvard.iq.dataverse.settings.JvmSettings;
import edu.harvard.iq.dataverse.util.file.BagItFileHandler;
import edu.harvard.iq.dataverse.util.file.CreateDataFileResult;
Expand Down Expand Up @@ -1478,25 +1479,17 @@ public static boolean canIngestAsTabular(String mimeType) {
}
}

/**
* Return the location where data should be stored temporarily after uploading (UI or API)
* for local processing (ingest, unzip, ...) and transfer to final destination (see storage subsystem).
*
* This location is checked to be configured, does exist, and is writeable via
* {@link ConfigCheckService#checkSystemDirectories()}.
*
* @return String with a path to the temporary location. Will not be null (former versions did to indicate failure)
*/
public static String getFilesTempDirectory() {

String filesRootDirectory = JvmSettings.FILES_DIRECTORY.lookup();
String filesTempDirectory = filesRootDirectory + "/temp";

if (!Files.exists(Paths.get(filesTempDirectory))) {
/* Note that "createDirectories()" must be used - not
* "createDirectory()", to make sure all the parent
* directories that may not yet exist are created as well.
*/
try {
Files.createDirectories(Paths.get(filesTempDirectory));
} catch (IOException ex) {
logger.severe("Failed to create filesTempDirectory: " + filesTempDirectory );
return null;
}
}

return filesTempDirectory;
return JvmSettings.FILES_DIRECTORY.lookup() + File.separator + "temp";
}

public static void generateS3PackageStorageIdentifier(DataFile dataFile) {
Expand Down

0 comments on commit a4ec3a6

Please sign in to comment.