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

fix: docker readonly fs #1058

Merged
merged 5 commits into from
Oct 9, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [9.2.3] - 2024-10-09

- Adds support for `--with-temp-dir` in CLI and `tempDirLocation=` in Core
- Adds validation to firstFactors and requiredSecondaryFactors names while creating tenants/apps/etc. to not allow
special chars.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class StartHandler extends CommandHandler {
public void doCommand(String installationDir, boolean viaInstaller, String[] args) {
String space = CLIOptionsParser.parseOption("--with-space", args);
String configPath = CLIOptionsParser.parseOption("--with-config", args);
String tempDirLocation = CLIOptionsParser.parseOption("--with-temp-dir", args);
if (configPath != null) {
configPath = new File(configPath).getAbsolutePath();
}
Expand Down Expand Up @@ -67,6 +68,9 @@ public void doCommand(String installationDir, boolean viaInstaller, String[] arg
if (forceNoInMemDB) {
commands.add("forceNoInMemDB=true");
}
if(tempDirLocation != null && !tempDirLocation.isEmpty()) {
commands.add("tempDirLocation=" + tempDirLocation);
}
} else {
commands.add(installationDir + "jre/bin/java");
commands.add("-Djava.security.egd=file:/dev/urandom");
Expand All @@ -90,6 +94,9 @@ public void doCommand(String installationDir, boolean viaInstaller, String[] arg
if (forceNoInMemDB) {
commands.add("forceNoInMemDB=true");
}
if(tempDirLocation != null && !tempDirLocation.isEmpty()) {
commands.add("tempDirLocation=" + tempDirLocation);
}
}
if (!foreground) {
try {
Expand Down Expand Up @@ -172,6 +179,8 @@ protected List<Option> getOptionsAndDescription() {
"Sets the host on which this instance of SuperTokens should run. Example: \"--host=192.168.0.1\""));
options.add(
new Option("--foreground", "Runs this instance of SuperTokens in the foreground (not as a daemon)"));
options.add(
new Option("--with-temp-dir", "Uses the passed dir as temp dir, instead of the internal default."));
return options;
}

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/io/supertokens/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ private void init() throws IOException, StorageQueryException {
Webserver.getInstance(this).start();

// this is a sign to the controlling script that this process has started.

createDotStartedFileForThisProcess();

// NOTE: If the message below is changed, make sure to also change the corresponding check in the CLI program
Expand Down Expand Up @@ -345,10 +346,11 @@ public void proceedToEnableFeatureFlag() {

private void createDotStartedFileForThisProcess() throws IOException {
CoreConfig config = Config.getBaseConfig(this);
String fileLocation = CLIOptions.get(this).getTempDirLocation() == null ? CLIOptions.get(this).getInstallationPath() : CLIOptions.get(this).getTempDirLocation();
sattvikc marked this conversation as resolved.
Show resolved Hide resolved
String fileName = OperatingSystem.getOS() == OperatingSystem.OS.WINDOWS
? CLIOptions.get(this).getInstallationPath() + ".started\\" + config.getHost(this) + "-"
? fileLocation + ".started\\" + config.getHost(this) + "-"
+ config.getPort(this)
: CLIOptions.get(this).getInstallationPath() + ".started/" + config.getHost(this) + "-"
: fileLocation + ".started/" + config.getHost(this) + "-"
+ config.getPort(this);
File dotStarted = new File(fileName);
if (!dotStarted.exists()) {
Expand Down
20 changes: 19 additions & 1 deletion src/main/java/io/supertokens/cliOptions/CLIOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,13 @@ public class CLIOptions extends ResourceDistributor.SingletonResource {
private static final String HOST_FILE_KEY = "host=";
private static final String TEST_MODE = "test_mode";
private static final String FORCE_NO_IN_MEM_DB = "forceNoInMemDB=true";
private static final String TEMP_DIR_LOCATION_KEY = "tempDirLocation=";
private final String installationPath;
private final String configFilePath;
private final Integer port;
private final String host;
private final String tempDirLocation;


// if this is true, then even in DEV mode, we will not use in memory db, even if there is an error in the plugin
private final boolean forceNoInMemoryDB;
Expand All @@ -44,6 +47,7 @@ private CLIOptions(String[] args) {
checkIfArgsIsCorrect(args);
String installationPath = args[0];
String configFilePathTemp = null;
String tempDirLocationPath = null;
Integer portTemp = null;
String hostTemp = null;
boolean forceNoInMemoryDBTemp = false;
Expand All @@ -54,7 +58,16 @@ private CLIOptions(String[] args) {
if (!new File(configFilePathTemp).isAbsolute()) {
throw new QuitProgramException("configPath option must be an absolute path only");
}
} else if (curr.startsWith(PORT_FILE_KEY)) {
} else if (curr.startsWith(TEMP_DIR_LOCATION_KEY)) {
tempDirLocationPath = curr.split(TEMP_DIR_LOCATION_KEY)[1];
if (!new File(tempDirLocationPath).isAbsolute()) {
throw new QuitProgramException("tempDirLocation option must be an absolute path only");
}
if(!tempDirLocationPath.isEmpty() && !tempDirLocationPath.endsWith(File.separator)){
tempDirLocationPath = tempDirLocationPath + File.separator;
}
}
else if (curr.startsWith(PORT_FILE_KEY)) {
portTemp = Integer.parseInt(curr.split(PORT_FILE_KEY)[1]);
} else if (curr.startsWith(HOST_FILE_KEY)) {
hostTemp = curr.split(HOST_FILE_KEY)[1];
Expand All @@ -69,6 +82,7 @@ private CLIOptions(String[] args) {
this.port = portTemp;
this.host = hostTemp;
this.forceNoInMemoryDB = forceNoInMemoryDBTemp;
this.tempDirLocation = tempDirLocationPath;
}

private static CLIOptions getInstance(Main main) {
Expand Down Expand Up @@ -123,4 +137,8 @@ public String getHost() {
public boolean isForceNoInMemoryDB() {
return this.forceNoInMemoryDB;
}

public String getTempDirLocation() {
return tempDirLocation;
}
}
32 changes: 27 additions & 5 deletions src/main/java/io/supertokens/webserver/Webserver.java
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.tomcat.util.http.fileupload.FileUtils;
import org.jetbrains.annotations.TestOnly;

import java.io.File;
import java.util.UUID;
Expand Down Expand Up @@ -101,11 +102,13 @@ public void start() {
return;
}

File webserverTemp = new File(CLIOptions.get(main).getInstallationPath() + "webserver-temp");
String tempDirLocation = decideTempDirLocation();
File webserverTemp = new File(tempDirLocation);
if (!webserverTemp.exists()) {
webserverTemp.mkdir();
webserverTemp.mkdirs();
}


CONTEXT_PATH = Config.getBaseConfig(main).getBasePath();

// this will make it so that if there is a failure, then tomcat will throw an
Expand All @@ -117,7 +120,7 @@ public void start() {
setupLogging();

// baseDir is a place for Tomcat to store temporary files..
tomcat.setBaseDir(CLIOptions.get(main).getInstallationPath() + TEMP_FOLDER);
tomcat.setBaseDir(tempDirLocation);

// set thread pool size and port
Connector connector = new Connector();
Expand All @@ -131,7 +134,7 @@ public void start() {
tomcat.getEngine().setName(main.getProcessId());

// create docBase folder and get context
new File(CLIOptions.get(main).getInstallationPath() + TEMP_FOLDER + "webapps").mkdirs();
new File(decideTempDirLocation() + "webapps").mkdirs();
StandardContext context = (StandardContext) tomcat.addContext(CONTEXT_PATH, "");

// the amount of time for which we should wait for all requests to finish when
Expand All @@ -158,6 +161,15 @@ public void start() {
setupRoutes();
}

private String decideTempDirLocation(){
String userSetTempDir = CLIOptions.get(main).getTempDirLocation();
if(userSetTempDir != null && !userSetTempDir.endsWith(File.separator)) {
userSetTempDir = userSetTempDir + File.separator;
}
String defaultTempDir = CLIOptions.get(main).getInstallationPath() + TEMP_FOLDER;
return userSetTempDir != null ? userSetTempDir : defaultTempDir;
}

private void setupRoutes() {
addAPI(new NotFoundOrHelloAPI(main));
addAPI(new HelloAPI(main));
Expand Down Expand Up @@ -307,7 +319,7 @@ public void stop() {
try {
// we want to clear just this process' folder and not all since other processes
// might still be running.
FileUtils.deleteDirectory(new File(CLIOptions.get(main).getInstallationPath() + TEMP_FOLDER));
FileUtils.deleteDirectory(new File(decideTempDirLocation()));
} catch (Exception ignored) {
}

Expand Down Expand Up @@ -353,6 +365,11 @@ public void closeLogger() {
}
}

@TestOnly
public TomcatReference getTomcatReference(){
return tomcatReference;
}

public static class TomcatReference {
private Tomcat tomcat;
private StandardContext context;
Expand All @@ -366,6 +383,11 @@ Tomcat getTomcat() {
return tomcat;
}

@TestOnly
public Tomcat getTomcatForTest(){
return tomcat;
}

StandardContext getContext() {
return context;
}
Expand Down
28 changes: 28 additions & 0 deletions src/test/java/io/supertokens/test/CLIOptionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -287,4 +287,32 @@ public void testMultipleInstancesAtTheSameTime() throws Exception {

}

@Test
public void cli2TempLocationTest() throws Exception {

String[] args = {"../"};

TestingProcess process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STARTED));

assertEquals(Config.getConfig(process.getProcess()).getHost(process.getProcess()), "localhost");
assertEquals(Config.getConfig(process.getProcess()).getPort(process.getProcess()), 3567);

process.kill();
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STOPPED));

//process starts with tempDirLocation param too.
args = new String[]{"../", "tempDirLocation=" + new File("../temp/").getAbsolutePath()};

process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STARTED));

assertEquals(Config.getConfig(process.getProcess()).getHost(process.getProcess()), "localhost");
assertEquals(Config.getConfig(process.getProcess()).getPort(process.getProcess()), 3567);

process.kill();
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STOPPED));

}

}
32 changes: 32 additions & 0 deletions src/test/java/io/supertokens/test/DotStartedFileTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,36 @@ public void processFailToStartDotStartedFileTest() throws Exception {
process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}

@Test
public void dotStartedFileAtTempDirLocation() throws Exception {
String tempDirLocation = new File("../temp/").getAbsolutePath();
String[] args = {"../", "tempDirLocation=" + tempDirLocation};

String host = "localhost";
String port = "8081";
String hostPortNameCheck = host + "-" + port;

Utils.setValueInConfig("port", port);

TestingProcessManager.TestingProcess process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STARTED));

File loc = new File(tempDirLocation + "/.started");

File[] dotStartedNameAndContent = loc.listFiles();
assert dotStartedNameAndContent != null;
assertEquals(1, dotStartedNameAndContent.length);
assertEquals(dotStartedNameAndContent[0].getName(), hostPortNameCheck);

String[] dotStartedContent = Files.readString(Paths.get(dotStartedNameAndContent[0].getPath())).split("\n");
String line = dotStartedContent[0];
assertEquals(line, Long.toString(ProcessHandle.current().pid()));
line = dotStartedContent.length > 1 ? dotStartedContent[1] : "";
assertEquals(line, Config.getConfig(process.main).getBasePath());
assertEquals(line, "");

process.kill();
assertNotNull(process.checkOrWaitForEvent(ProcessState.PROCESS_STATE.STOPPED));
}
}
21 changes: 21 additions & 0 deletions src/test/java/io/supertokens/test/WebserverTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,15 @@
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.catalina.startup.Tomcat;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
import org.mockito.Mockito;

import java.io.File;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetAddress;
Expand Down Expand Up @@ -963,6 +965,25 @@ public void validBasePath() throws InterruptedException, IOException, HttpRespon

}

@Test
public void tempDirLocationWebserverStarts() throws InterruptedException, HttpResponseException, IOException {
String tempDirLocation = new File("../temp/").getCanonicalPath();
String[] args = {"../", "tempDirLocation=" + tempDirLocation};
TestingProcess process = TestingProcessManager.start(args);
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STARTED));

Webserver.TomcatReference reference = Webserver.getInstance(process.getProcess()).getTomcatReference();
File catalinaBase = reference.getTomcatForTest().getServer().getCatalinaBase();
assertEquals(tempDirLocation, catalinaBase.getAbsolutePath());

String response = HttpRequest.sendGETRequest(process.getProcess(), "", "http://localhost:3567/", null,
1000, 1000, null);
assertEquals("Hello", response);

process.kill();
assertNotNull(process.checkOrWaitForEvent(PROCESS_STATE.STOPPED));
}

@Test
public void validBasePathWithEmptyHelloPath() throws InterruptedException, IOException, HttpResponseException {
{
Expand Down
Loading