summaryrefslogtreecommitdiffstats
path: root/dozentenmodulserver
diff options
context:
space:
mode:
authorStephan Schwär2020-12-11 00:49:46 +0100
committerStephan Schwär2020-12-11 00:49:46 +0100
commitf0a78f80e0096732a30904a3e3d383b60b70e25c (patch)
tree2d0ca9f54423373ef7525be9398e46ff8a28d6e0 /dozentenmodulserver
parent[client] Prevent scaling of fonts multiple times (diff)
parent[client] improved htmleditor in imageMetadataPage (diff)
downloadtutor-module-f0a78f80e0096732a30904a3e3d383b60b70e25c.tar.gz
tutor-module-f0a78f80e0096732a30904a3e3d383b60b70e25c.tar.xz
tutor-module-f0a78f80e0096732a30904a3e3d383b60b70e25c.zip
Merge remote-tracking branch 'origin/feature/htmlEditorInDescrioptionText' into feature-merge
Diffstat (limited to 'dozentenmodulserver')
-rw-r--r--dozentenmodulserver/pom.xml4
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java18
-rw-r--r--dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java3
-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
5 files changed, 146 insertions, 14 deletions
diff --git a/dozentenmodulserver/pom.xml b/dozentenmodulserver/pom.xml
index f660d51d..ac41c772 100644
--- a/dozentenmodulserver/pom.xml
+++ b/dozentenmodulserver/pom.xml
@@ -38,8 +38,8 @@
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
- <source>1.7</source>
- <target>1.7</target>
+ <source>1.8</source>
+ <target>1.8</target>
</configuration>
</plugin>
<plugin>
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java
index 36c3a466..da52a5b3 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbImage.java
@@ -1097,4 +1097,22 @@ public class DbImage {
}
}
+ /**
+ * Get all known file names of images, regardless of whether they are working/valid.
+ */
+ public static Set<String> getAllFilenames() throws SQLException {
+ try (MysqlConnection connection = Database.getConnection()) {
+ MysqlStatement stmt = connection.prepareStatement("SELECT filepath FROM imageversion");
+ ResultSet rs = stmt.executeQuery();
+ Set<String> result = new HashSet<>();
+ while (rs.next()) {
+ result.add(rs.getString("filepath"));
+ }
+ return result;
+ } catch (SQLException e) {
+ LOGGER.error("Query failed in DbImage.getAllFilenames()", e);
+ throw e;
+ }
+ }
+
}
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java
index 4ecb9d99..c07a0ed9 100644
--- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java
+++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java
@@ -30,7 +30,6 @@ import org.openslx.bwlp.thrift.iface.TNotFoundException;
import org.openslx.bwlp.thrift.iface.UserInfo;
import org.openslx.util.Json;
import org.openslx.util.Util;
-import org.openslx.util.vm.UnsupportedVirtualizerFormatException;
import org.openslx.util.vm.VmMetaData;
import org.openslx.util.vm.VmMetaData.UsbSpeed;
@@ -553,7 +552,7 @@ public class DbLecture {
}
public static LaunchData getClientLaunchData(String lectureId) throws SQLException,
- TNotFoundException, UnsupportedVirtualizerFormatException {
+ TNotFoundException {
LaunchData retval = new LaunchData();
byte[] config;
String lectureName;
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");
}
/**