diff options
| author | Simon Rettberg | 2016-01-14 17:43:02 +0100 |
|---|---|---|
| committer | Simon Rettberg | 2016-01-14 17:43:02 +0100 |
| commit | 3578c2cdf4bba9a73d57a64941ebc2e4c931e555 (patch) | |
| tree | 622e50e698663f288f6b7d9d51a610f23218a831 /dozentenmodulserver/src/main/java | |
| parent | [server] Remove stupid debug output (diff) | |
| download | tutor-module-3578c2cdf4bba9a73d57a64941ebc2e4c931e555.tar.gz tutor-module-3578c2cdf4bba9a73d57a64941ebc2e4c931e555.tar.xz tutor-module-3578c2cdf4bba9a73d57a64941ebc2e4c931e555.zip | |
[server] Add location support/filtering
Diffstat (limited to 'dozentenmodulserver/src/main/java')
5 files changed, 154 insertions, 13 deletions
diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java index 2d9e73c9..8e615ef1 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/App.java @@ -3,6 +3,7 @@ package org.openslx.bwlp.sat; import java.io.IOException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; +import java.sql.SQLException; import java.util.HashSet; import java.util.Set; @@ -13,6 +14,7 @@ import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.thrift.transport.TTransportException; +import org.openslx.bwlp.sat.database.Updater; import org.openslx.bwlp.sat.database.mappers.DbUser; import org.openslx.bwlp.sat.fileserv.FileServer; import org.openslx.bwlp.sat.maintenance.DeleteOldImages; @@ -40,8 +42,9 @@ public class App { public static void main(String[] args) throws TTransportException, NoSuchAlgorithmException, IOException, KeyManagementException { - //get going and show basic information in log file - BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%d %-5p [%t] %C{1} - %m%n"))); + // get going and show basic information in log file + // don't add date/time to log output - will be done by syslog + BasicConfigurator.configure(new ConsoleAppender(new PatternLayout("%-5p [%t] %C{1} - %m%n"))); if (args.length != 0 && args[0].equals("debug")) { DEBUG = true; } @@ -58,6 +61,14 @@ public class App { System.exit(1); } + // Update database schema if applicable + try { + Updater.updateDatabase(); + } catch (SQLException e1) { + LOGGER.fatal("Updating/checking the database layout failed."); + return; + } + if (Identity.loadCertificate() == null) { LOGGER.error("Could not set up TLS/SSL requirements, exiting"); System.exit(1); 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 0ed62770..1f0daf66 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 @@ -63,6 +63,8 @@ public class DbLecture { stmt.setString("imageversionid", lecture.imageVersionId); stmt.setBoolean("autoupdate", lecture.autoUpdate); stmt.setBoolean("isenabled", lecture.isEnabled); + stmt.setBoolean("isprivate", lecture.limitToAllowedUsers); + stmt.setBoolean("islocationprivate", lecture.limitToLocations); stmt.setLong("starttime", lecture.startTime); stmt.setLong("endtime", lecture.endTime); stmt.setString("updaterid", updatingUser.userId); @@ -75,22 +77,41 @@ public class DbLecture { stmt.setBoolean("canadmindefault", lecture.defaultPermissions.admin); } + private static void writeLocations(MysqlConnection connection, String lectureId, List<Integer> locationIds) + throws SQLException { + MysqlStatement delStmt = connection.prepareStatement("DELETE FROM lecture_x_location WHERE lectureid = :lectureid"); + delStmt.setString("lectureid", lectureId); + delStmt.executeUpdate(); + if (locationIds == null || locationIds.isEmpty()) + return; + MysqlStatement addStmt = connection.prepareStatement("INSERT IGNORE INTO lecture_x_location (lectureid, locationid)" + + " VALUES (:lectureid, :locationid)"); + addStmt.setString("lectureid", lectureId); + for (Integer locationId : locationIds) { + addStmt.setInt("locationid", locationId); + addStmt.executeUpdate(); + } + } + public static String create(UserInfo user, LectureWrite lecture) throws SQLException { try (MysqlConnection connection = Database.getConnection()) { MysqlStatement stmt = connection.prepareStatement("INSERT INTO lecture" + " (lectureid, displayname, description, imageversionid, autoupdate," + " isenabled, starttime, endtime, createtime, updatetime," + + " isprivate, islocationprivate," + " ownerid, updaterid, runscript, nics, netrules, isexam," + " hasinternetaccess, caneditdefault, canadmindefault)" + " VALUES " + " (:lectureid, :displayname, :description, :imageversionid, :autoupdate," + " :isenabled, :starttime, :endtime, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()," + + " :isprivate, :islocationprivate," + " :ownerid, :updaterid, :runscript, :nics, :netrules, :isexam," + " :hasinternetaccess, :caneditdefault, :canadmindefault)"); String lectureId = UUID.randomUUID().toString(); setWriteFields(stmt, lectureId, lecture, user); stmt.setString("ownerid", user.userId); stmt.executeUpdate(); + writeLocations(connection, lectureId, lecture.locationIds); connection.commit(); return lectureId; } catch (SQLException e) { @@ -105,11 +126,13 @@ public class DbLecture { + " displayname = :displayname, description = :description, imageversionid = :imageversionid," + " autoupdate = :autoupdate, isenabled = :isenabled, starttime = :starttime," + " endtime = :endtime, updatetime = UNIX_TIMESTAMP()," + + " isprivate = :isprivate, islocationprivate = :islocationprivate," + " updaterid = :updaterid, runscript = :runscript, nics = :nics," + " netrules = :netrules, isexam = :isexam, hasinternetaccess = :hasinternetaccess," + " caneditdefault = :caneditdefault, canadmindefault = :canadmindefault" + " WHERE lectureid = :lectureid"); setWriteFields(stmt, lectureId, lecture, user); + writeLocations(connection, lectureId, lecture.locationIds); stmt.executeUpdate(); } @@ -241,6 +264,7 @@ public class DbLecture { + " l.lectureid, l.displayname AS lecturename, l.description, l.imageversionid, i.imagebaseid," + " l.autoupdate, l.isenabled, l.starttime, l.endtime, l.lastused, l.usecount, l.createtime," + " l.updatetime, l.ownerid, l.updaterid, l.runscript, l.nics, l.netrules, l.isexam," + + " l.isprivate, l.islocationprivate," + " l.hasinternetaccess, l.caneditdefault, l.canadmindefault, p.canedit, p.canadmin" + " FROM lecture l " + " LEFT JOIN imageversion i USING (imageversionid)" @@ -259,6 +283,8 @@ public class DbLecture { lecture.setImageBaseId(rs.getString("imagebaseid")); lecture.setAutoUpdate(rs.getBoolean("autoupdate")); lecture.setIsEnabled(rs.getBoolean("isenabled")); + //lecture.setLimitToAllowedUsers(rs.getBoolean("isprivate")); + //lecture.setLimitToLocations(rs.getBoolean("islocationprivate")); TODO lecture.setStartTime(rs.getLong("starttime")); lecture.setEndTime(rs.getLong("endtime")); lecture.setLastUsed(rs.getLong("lastused")); @@ -286,6 +312,7 @@ public class DbLecture { lecture.setDefaultPermissions(DbLecturePermissions.fromResultSetDefault(rs)); lecture.setUserPermissions(DbLecturePermissions.fromResultSetUser(rs)); User.setCombinedUserPermissions(lecture, user); + // TODO: Query locations return lecture; } catch (SQLException e) { LOGGER.error("Query failed in DbLecture.getLectureDetails()", e); @@ -407,10 +434,37 @@ public class DbLecture { } } - public static VmChooserListXml getUsableListXml(boolean exams) throws SQLException { + public static VmChooserListXml getUsableListXml(boolean exams, String locationsString) throws SQLException { + // Sanitize and clean locations string + // Input is in the form of "1 2 3 4" or "1" or " 1 4 5" + // We want "1,2,3,4" or "1" or "1,4,5" + // Do this since we embed this directly into the query + String cleanLocations = null; + if (Util.isEmptyString(locationsString)) { + cleanLocations = "0"; + } else if (locationsString.indexOf(' ') == -1) { + cleanLocations = Integer.toString(org.openslx.util.Util.parseInt(locationsString, 0)); + } else { + String[] array = locationsString.split(" +"); + for (String loc : array) { + int val = org.openslx.util.Util.parseInt(loc, -1); + if (val == -1) + continue; + if (cleanLocations == null) { + cleanLocations = Integer.toString(val); + } else { + cleanLocations += "," + Integer.toString(val); + } + } + if (cleanLocations == null) { + cleanLocations = "0"; + } + } + // Query try (MysqlConnection connection = Database.getConnection()) { MysqlStatement stmt = connection.prepareStatement("SELECT" + " l.lectureid, l.displayname AS lecturename, l.description," + + " l.islocationprivate, loc.lectureid AS loctest," + " l.endtime, l.usecount, o.displayname AS osname, v.virtname, b.istemplate," + " v.virtid, ov.virtoskeyword, i.filepath" + " FROM lecture l " @@ -419,13 +473,26 @@ public class DbLecture { + " INNER JOIN operatingsystem o USING (osid)" + " INNER JOIN virtualizer v USING (virtid)" + " LEFT JOIN os_x_virt ov USING (osid, virtid)" + + " LEFT JOIN (" + + " SELECT DISTINCT lectureid FROM lecture_x_location WHERE locationid IN (" + cleanLocations + ")" + + " ) loc USING (lectureid)" + " WHERE l.isenabled = 1 AND l.isprivate = 0 AND l.isexam = :isexam" + " AND l.starttime < UNIX_TIMESTAMP() AND l.endtime > UNIX_TIMESTAMP() AND i.isvalid = 1"); stmt.setBoolean("isexam", exams); ResultSet rs = stmt.executeQuery(); VmChooserListXml list = new VmChooserListXml(true); while (rs.next()) { - String prio = rs.getBoolean("istemplate") ? "10" : "100"; + boolean isForThisLocation = rs.getString("loctest") != null; + if (!isForThisLocation && rs.getBoolean("islocationprivate")) + continue; // Is limited to location, and we're not in one of the required locations + String prio; + if (isForThisLocation) { + prio = "40"; + } else if (rs.getBoolean("istemplate")) { + prio = "60"; + } else { + prio = "80"; + } list.add(new VmChooserEntryXml(rs.getString("filepath"), prio, "-", rs.getString("lecturename"), rs.getString("description"), rs.getString("lectureid"), rs.getString("virtid"), rs.getString("virtname"), rs.getString("virtoskeyword"), diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java index a1a9dacf..d24bb912 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/thrift/ServerHandler.java @@ -14,6 +14,7 @@ import org.openslx.bwlp.sat.database.mappers.DbImage.DeleteState; import org.openslx.bwlp.sat.database.mappers.DbImagePermissions; import org.openslx.bwlp.sat.database.mappers.DbLecture; import org.openslx.bwlp.sat.database.mappers.DbLecturePermissions; +import org.openslx.bwlp.sat.database.mappers.DbLocation; import org.openslx.bwlp.sat.database.mappers.DbUser; import org.openslx.bwlp.sat.database.models.ImageVersionMeta; import org.openslx.bwlp.sat.database.models.LocalImageVersion; @@ -635,8 +636,12 @@ public class ServerHandler implements SatelliteServer.Iface { @Override public List<Location> getLocations() throws TException { - // TODO Auto-generated method stub - return null; + try { + return DbLocation.getLocations(); + } catch (SQLException e) { + throw new TInvocationException(InvocationError.INTERNAL_SERVER_ERROR, + "Database failure when retrieving list"); + } } } diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Configuration.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Configuration.java index c8208338..5dd9b8ec 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Configuration.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/util/Configuration.java @@ -23,6 +23,7 @@ public class Configuration { private static String masterAddress; private static boolean masterSsl = true; private static int masterPort = 9091; + private static String dbLocationTable; public static boolean load() throws IOException { // Load configuration from java properties file @@ -39,6 +40,7 @@ public class Configuration { dbUri = prop.getProperty("db.uri"); dbUsername = prop.getProperty("db.username"); dbPassword = prop.getProperty("db.password"); + dbLocationTable = prop.getProperty("db.location-table"); masterAddress = prop.getProperty("master.address"); if (!Util.isEmptyString(prop.getProperty("master.ssl"))) { masterSsl = Boolean.getBoolean(prop.getProperty("master.ssl")); @@ -75,6 +77,10 @@ public class Configuration { public static String getDbPassword() { return dbPassword; } + + public static String getDbLocationTable() { + return dbLocationTable; + } public static File getVmStoreProdPath() { return vmStoreProdPath; 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 37a64ee8..5f82bac1 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 @@ -3,6 +3,9 @@ package org.openslx.bwlp.sat.web; import java.io.ByteArrayInputStream; import java.io.IOException; import java.sql.SQLException; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.log4j.Logger; @@ -21,23 +24,66 @@ public class WebServer extends NanoHTTPD { private static final Logger LOGGER = Logger.getLogger(WebServer.class); - private static final GenericDataCache<byte[]> lectureListCache = new GenericDataCache<byte[]>(15000) { - Serializer serializer = new Persister(); + private static final int LIST_CACHE_MS = 15000; + private static final int LIST_CACHE_MAX_ENTRIES = 16; + + private static final Map<String, XmlDataCache> lectureListCache = Collections.synchronizedMap(new LinkedHashMap<String, XmlDataCache>() { + private static final long serialVersionUID = -8461839969909678055L; + + @Override + protected boolean removeEldestEntry(Map.Entry<String, XmlDataCache> eldest) { + return size() > LIST_CACHE_MAX_ENTRIES; + } + }); + + private static final Serializer serializer = new Persister(); + + private class XmlDataCache extends GenericDataCache<byte[]> { + + private final String locationId; + + public XmlDataCache(String locations) { + super(LIST_CACHE_MS); + this.locationId = locations; + } @Override protected byte[] update() throws Exception { - VmChooserListXml listXml = DbLecture.getUsableListXml(false); + VmChooserListXml listXml = DbLecture.getUsableListXml(false, locationId); ByteArrayOutputStream baos = new ByteArrayOutputStream(); serializer.write(listXml, baos); return baos.toByteArray(); } - }; + + } public WebServer(int port) { super("127.0.0.1", port); super.maxRequestSize = 65535; } + /** + * Extract request source ip address. Honors the x-forwarded-for header. + * + * @param headers map of headers as supplied by nanohttpd + * @return IP address, or empty string if unknown + */ + private String extractIp(Map<String, String> headers) { + String ip; + ip = headers.get("remote-addr"); + if (ip != null && !ip.equals("127.0.0.1")) + return ip; + if (headers == null || headers.isEmpty()) + return ""; + ip = headers.get("x-forwarded-for"); + if (ip == null || ip.isEmpty()) + return ""; + final int i = ip.lastIndexOf(','); + if (i == -1) + return ip.trim(); + return ip.substring(i + 1).trim(); + } + @Override public Response serve(IHTTPSession session) { String uri = session.getUri(); @@ -61,7 +107,7 @@ public class WebServer extends NanoHTTPD { private Response handle(IHTTPSession session, String uri) { // Our special stuff if (uri.startsWith("/vmchooser/list")) { - return serveVmChooserList(); + return serveVmChooserList(session.getParms()); } if (uri.startsWith("/vmchooser/lecture/")) { return serveLectureStart(uri.substring(19)); @@ -106,9 +152,15 @@ public class WebServer extends NanoHTTPD { new ByteArrayInputStream(meta.getFilteredDefinitionArray())); } - private Response serveVmChooserList() { + private Response serveVmChooserList(Map<String, String> params) { + String locations = params.get("locations"); + XmlDataCache cache = lectureListCache.get(locations); + if (cache == null) { + cache = new XmlDataCache(locations); + lectureListCache.put(locations, cache); + } return new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, "text/xml; charset=utf-8", - new ByteArrayInputStream(lectureListCache.get())); + new ByteArrayInputStream(cache.get())); } public static Response internalServerError() { |
