summaryrefslogtreecommitdiffstats
path: root/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web
diff options
context:
space:
mode:
Diffstat (limited to 'dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web')
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java123
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java12
2 files changed, 125 insertions, 10 deletions
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java
index 0e47994a..3a6f39ad 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebRpc.java
@@ -5,16 +5,25 @@ import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
+import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import javax.security.auth.login.LoginException;
import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.log4j.Logger;
import org.openslx.bwlp.sat.database.mappers.DbConfiguration;
+import org.openslx.bwlp.sat.database.mappers.DbImage;
import org.openslx.bwlp.sat.mail.MailTemplate;
import org.openslx.bwlp.sat.mail.MailTemplatePlain.Template;
import org.openslx.bwlp.sat.mail.SmtpMailer;
@@ -23,6 +32,8 @@ import org.openslx.bwlp.sat.maintenance.DeleteOldImages;
import org.openslx.bwlp.sat.maintenance.ImageValidCheck;
import org.openslx.bwlp.sat.maintenance.ImageValidCheck.CheckResult;
import org.openslx.bwlp.sat.maintenance.ImageValidCheck.SubmitResult;
+import org.openslx.bwlp.sat.util.Configuration;
+import org.openslx.bwlp.sat.util.FileSystem;
import org.openslx.util.Json;
import org.openslx.util.Util;
@@ -31,6 +42,8 @@ import fi.iki.elonen.NanoHTTPD.Response;
public class WebRpc {
+ private static final Logger LOGGER = Logger.getLogger(WebRpc.class);
+
public static Response handle(String uri, Map<String, String> params) {
if (uri.equals("mailtest")) {
return mailTest(params);
@@ -47,6 +60,9 @@ public class WebRpc {
if (uri.equals("reset-mail-templates")) {
return resetMailTemplates();
}
+ if (uri.equals("scan-orphaned-files")) {
+ return scanForOrphanedFiles(params);
+ }
return WebServer.notFound();
}
@@ -55,6 +71,102 @@ public class WebRpc {
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/plain; charset=utf-8", "OK");
}
+ /**
+ * Scan the vmstore for orphaned files and images, return a list.
+ * If POST param 'action' is 'delete', all those files will be deleted.
+ */
+ private static Response scanForOrphanedFiles(Map<String, String> params) {
+ if (!FileSystem.isStorageMounted())
+ return WebServer.internalServerError("VMstore not mounted");
+ final Map<String, DeleteResult> orphanedFiles = new HashMap<>();
+ final String baseDir = Configuration.getVmStoreBasePath().toString();
+ final int baseLen = baseDir.length() + (baseDir.endsWith("/") ? 0 : 1);
+ final boolean del = params.containsKey("action") && params.get("action").equals("delete");
+ final Set<String> known; // These we want to keep
+ try {
+ known = DbImage.getAllFilenames();
+ } catch (SQLException e1) {
+ return WebServer.internalServerError("Cannot query list of known images from database");
+ }
+ if (known.isEmpty()) {
+ return WebServer.internalServerError("SAFTY CHECK: Known image list empty, aborting");
+ }
+ AtomicInteger matches = new AtomicInteger();
+ try {
+ // Consider only regular files, call checkFile for each one
+ Files.find(Configuration.getVmStoreProdPath().toPath(), 8,
+ (filePath, fileAttr) -> fileAttr.isRegularFile())
+ .forEach((fileName) -> checkFile(fileName, orphanedFiles, baseLen, known, matches));
+ } catch (IOException e) {
+ return WebServer.internalServerError(e.toString());
+ }
+ if (del) {
+ for (Entry<String, DeleteResult> it : orphanedFiles.entrySet()) {
+ if (matches.get() == 0) {
+ // Don't delete anything if the set of known files and the set of files we actually
+ // found are disjoint
+ it.setValue(DeleteResult.SAFETY_ABORT);
+ continue;
+ }
+ Path filePath = Paths.get(baseDir + "/" + it.getKey());
+ try {
+ Files.delete(filePath);
+ it.setValue(DeleteResult.DELETED);
+ } catch (Exception e) {
+ LOGGER.warn("Cannot delete " + filePath, e);
+ it.setValue(DeleteResult.ERROR);
+ }
+ }
+ }
+ return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "application/json; charset=utf-8",
+ Json.serialize(orphanedFiles));
+ }
+
+ private static enum DeleteResult {
+ EXISTS,
+ DELETED,
+ ERROR,
+ SAFETY_ABORT;
+ }
+
+ /**
+ * Function called for each file found on the VMstore to determine if it's
+ * orphaned.
+ *
+ * @param filePath File to check
+ * @param result Map to add the check result to
+ * @param baseLen length of the base path we need to strip from the absolute
+ * path
+ * @param known list of known images from the db
+ * @param matches counter for files that match a DB entry
+ */
+ private static void checkFile(Path filePath, Map<String, DeleteResult> result, int baseLen,
+ Set<String> known, AtomicInteger matches) {
+ if (filePath.endsWith("dozmod.lock"))
+ return;
+ final String relativeFileName;
+ try {
+ relativeFileName = filePath.toAbsolutePath().toString().substring(baseLen);
+ } catch (IndexOutOfBoundsException e) {
+ LOGGER.warn("Cannot make image path relative", e);
+ return;
+ }
+ // Handle special dnbd3 files
+ String compareFileName;
+ if (relativeFileName.endsWith(".crc") || relativeFileName.endsWith(".map")) {
+ compareFileName = relativeFileName.substring(0, relativeFileName.length() - 4);
+ } else if (relativeFileName.endsWith(".meta")) {
+ compareFileName = relativeFileName.substring(0, relativeFileName.length() - 5);
+ } else {
+ compareFileName = relativeFileName;
+ }
+ if (known.contains(compareFileName)) {
+ matches.incrementAndGet();
+ } else {
+ result.put(relativeFileName, DeleteResult.EXISTS);
+ }
+ }
+
private static Response checkImage(Map<String, String> params) {
String versionId = params.get("versionid");
if (versionId == null)
@@ -88,7 +200,8 @@ public class WebRpc {
StringBuilder res = DeleteOldImages.hardDeleteImages();
if (res == null)
return WebServer.internalServerError();
- return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/plain; charset=utf-8", res.toString());
+ return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/plain; charset=utf-8",
+ res.toString());
}
/**
@@ -132,11 +245,9 @@ public class WebRpc {
}
smtpc = null;
}
-
boolean ret = false;
- if (smtpc != null) {
-
+ if (smtpc != null) {
MailTemplate template = DbConfiguration.getMailTemplate(Template.TEST_MAIL);
Map<String, String> templateArgs = new HashMap<>();
templateArgs.put("host", host);
@@ -149,8 +260,8 @@ public class WebRpc {
ret = smtpc.send(recipient, "bwLehrpool Mail Test", msg, "<sat.bwlehrpool.de>");
}
try {
- baos.write(("\n\n-----------------------------------------\nTestergebnis: " + (ret ? "" : "nicht ")
- + "erfolgreich").getBytes(StandardCharsets.UTF_8));
+ baos.write(("\n\n-----------------------------------------\nTestergebnis: "
+ + (ret ? "" : "nicht ") + "erfolgreich").getBytes(StandardCharsets.UTF_8));
} catch (IOException e) {
}
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/plain; charset=utf-8",
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java
index 3e91cfc5..6357e411 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/web/WebServer.java
@@ -31,7 +31,6 @@ import org.openslx.bwlp.thrift.iface.TNotFoundException;
import org.openslx.util.GrowingThreadPoolExecutor;
import org.openslx.util.Json;
import org.openslx.util.Util;
-import org.openslx.util.vm.UnsupportedVirtualizerFormatException;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
@@ -167,7 +166,7 @@ public class WebServer extends NanoHTTPD {
final LaunchData ld;
try {
ld = DbLecture.getClientLaunchData(lectureId);
- } catch (UnsupportedVirtualizerFormatException | TNotFoundException e) {
+ } catch (TNotFoundException e) {
// TODO better virt error handling
return notFound();
} catch (SQLException e) {
@@ -288,10 +287,15 @@ public class WebServer extends NanoHTTPD {
/**
* Helper for returning "Internal Server Error" Status
+ * @param body Message
*/
- public static Response internalServerError() {
+ public static Response internalServerError(String body) {
return new NanoHTTPD.Response(NanoHTTPD.Response.Status.INTERNAL_ERROR, "text/plain",
- "Internal Server Error");
+ body);
+ }
+
+ public static Response internalServerError() {
+ return internalServerError("Internal Server Error");
}
/**