From 5e39c0040ddde260831a5b9f73c0bbfec3738f94 Mon Sep 17 00:00:00 2001
From: Kai Reinhard <K.Reinhard@micromata.de>
Date: Tue, 13 Apr 2021 23:20:23 +0000
Subject: [PATCH] Docker...
---
.gitignore | 1
borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java | 7 +
borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java | 21 ++++
borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java | 3
README.adoc | 4
borgbutler-core/README.adoc | 4
borgbutler-docker/buildDocker.sh | 15 +++
borgbutler-server/src/main/resources/log4j.properties | 2
borgbutler-server/src/main/java/de/micromata/borgbutler/server/jetty/JettyServer.java | 22 +++-
build.gradle | 2
borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java | 20 +++
borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgVersionTest.java | 20 ++++
borgbutler-docker/app/Dockerfile | 35 +++++++
borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgVersion.java | 53 +++++++++
borgbutler-server/src/main/java/de/micromata/borgbutler/server/user/UserFilter.java | 44 ++++++--
15 files changed, 221 insertions(+), 32 deletions(-)
diff --git a/.gitignore b/.gitignore
index 611c1f7..6aba3e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,3 +41,4 @@
borgbutler-server/out
borgbutler-webapp/build
borgbutler-webapp/node_modules
+borgbutler-docker/app/target
diff --git a/README.adoc b/README.adoc
index a4e947f..70bdc88 100644
--- a/README.adoc
+++ b/README.adoc
@@ -38,7 +38,7 @@
== Build and start from command line
=== Build distribution and start with Gradle
-1. `cd borgbackup-butler`
+1. `cd borgbackup-butler/borgbutler-webapp`
2. `npm install`
3. `cd ..`
4. `gradle distZip`
@@ -92,4 +92,4 @@
== Install server
=== Debian
-tbd.
\ No newline at end of file
+tbd.
diff --git a/borgbutler-core/README.adoc b/borgbutler-core/README.adoc
index 1074d70..a26d3c2 100644
--- a/borgbutler-core/README.adoc
+++ b/borgbutler-core/README.adoc
@@ -4,7 +4,7 @@
:toc:
:toclevels: 4
-Copyright (C) 2019
+Copyright (C) 2019-2021
ifdef::env-github,env-browser[:outfilesuffix: .adoc]
@@ -18,4 +18,4 @@
4. Execute script `./createFiles.sh` as root on debian host (borg is installed automatically)
5. See and get the result files in `out.tar`:
.. `cp out.tar /home/borgbutler`
- .. From host system: `scp -P 2222 borgbutler@127.0.0.1:out.tar`
\ No newline at end of file
+ .. From host system: `scp -P 2222 borgbutler@127.0.0.1:out.tar`
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
index 661e01f..b13063d 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/Configuration.java
@@ -11,6 +11,9 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * Representation of ~/.borgbutler/borgbutler-config.json.
+ */
public class Configuration {
private Logger log = LoggerFactory.getLogger(Configuration.class);
/**
@@ -21,11 +24,16 @@
@JsonIgnore
private File workingDir;
/**
- * The path of the borg command to use.
+ * The path of the borg command to use (optional).
*/
private String borgCommand;
/**
+ * The borg version to install from github (optional).
+ */
+ private String borgVersion;
+
+ /**
* Default is 100 MB (approximately).
*/
private int maxArchiveContentCacheCapacityMb = 100;
@@ -105,10 +113,17 @@
return repoConfigs;
}
+ /**
+ * Optional borg command to use.
+ */
public String getBorgCommand() {
return this.borgCommand;
}
+ public String getBorgVersion() {
+ return borgVersion;
+ }
+
public int getMaxArchiveContentCacheCapacityMb() {
return this.maxArchiveContentCacheCapacityMb;
}
@@ -131,6 +146,10 @@
return this;
}
+ public void setBorgVersion(String borgVersion) {
+ this.borgVersion = borgVersion;
+ }
+
public Configuration setShowDemoRepos(boolean showDemoRepos) {
this.showDemoRepos = showDemoRepos;
return this;
diff --git a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
index ee1fb32..e6c82e9 100644
--- a/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
+++ b/borgbutler-core/src/main/java/de/micromata/borgbutler/config/ConfigurationHandler.java
@@ -20,9 +20,17 @@
private File configFile;
private File configBackupDir;
private File workingDir;
+ private File butlerHomeDir;
private Configuration configuration;
private static Class<? extends Configuration> configClazz = Configuration.class;
+ public static void init(String butlerHomeDir) {
+ if (instance != null) {
+ throw new RuntimeException("ConfigurationHandler already initialized");
+ }
+ instance = new ConfigurationHandler(butlerHomeDir);
+ }
+
public static ConfigurationHandler getInstance() {
if (instance == null) instance = new ConfigurationHandler();
return instance;
@@ -97,8 +105,16 @@
}
private ConfigurationHandler() {
- File userHome = new File(System.getProperty("user.home"));
- workingDir = new File(userHome, BUTLER_HOME_DIR);
+ this(null);
+ }
+
+ private ConfigurationHandler(String butlerHomeDir) {
+ if (butlerHomeDir != null) {
+ workingDir = new File(butlerHomeDir);
+ } else {
+ workingDir = new File(System.getProperty("user.home"), BUTLER_HOME_DIR);
+ }
+ log.info("Using directory '" + workingDir.getAbsolutePath() + "' as BorgButler's home directory.");
if (!workingDir.exists()) {
log.info("Creating borg-butlers working directory: " + workingDir.getAbsolutePath());
workingDir.mkdirs();
diff --git a/borgbutler-docker/app/Dockerfile b/borgbutler-docker/app/Dockerfile
new file mode 100644
index 0000000..49a3341
--- /dev/null
+++ b/borgbutler-docker/app/Dockerfile
@@ -0,0 +1,35 @@
+FROM openjdk:11
+
+# See: https://spring.io/guides/gs/spring-boot-docker/
+
+# This is a Debian system, update system packages (if needed)
+RUN apt-get update && apt-get -y upgrade
+
+RUN addgroup borgbutler && adduser --ingroup borgbutler borgbutler
+# ProjectForge's base dir: must be mounted on host file system:
+RUN mkdir /BorgButler
+# Grant access for user projectforge:
+RUN chown borgbutler.borgbutler /BorgButler
+VOLUME /BorgButler
+EXPOSE 9042
+
+USER borgbutler:borgbutler
+
+# Don't put fat jar files in docker images: https://phauer.com/2019/no-fat-jar-in-docker-image/
+ARG DEPENDENCY=target/dependency/borgbutler-server-0.3-SNAPSHOT
+COPY ${DEPENDENCY}/lib /app/lib
+COPY ${DEPENDENCY}/web /app/web
+#COPY ${DEPENDENCY}/META-INF /app/META-INF
+#COPY ${DEPENDENCY}/BOOT-INF/classes /app
+
+#ARG JAVA_OPTS="-Xms1g -Xmx1g"
+#ENV JAVA_OPTS_VAR=$JAVA_OPTS
+
+# -Dloader.path=${HOME}/ProjectForge/resources/milton ${DEBUGOPTS}
+
+# Variable expansion doesn't work for ENTRYPOINT definition as array, but array is required, because graceful shutdown of
+# container isn't given if java is started via 'sh -c' as it will be done by ENTRYPOINT java .....
+# Java options are modifiable by user through own ENTRYPOINT definition on docker run or in docker-compose.yml.
+ENTRYPOINT ["java", "-Xms1g", "-Xmx1g", "-cp", "app/web/*:app/lib/*", "-DborgbutlerHome=/BorgButler/", "-DapplicationHome=/app", "-DbindAddress=0.0.0.0", "-DallowedClientIps=172.17.", "de.micromata.borgbutler.server.Main", "-q"]
+
+MAINTAINER Micromata
diff --git a/borgbutler-docker/buildDocker.sh b/borgbutler-docker/buildDocker.sh
new file mode 100755
index 0000000..3072f3e
--- /dev/null
+++ b/borgbutler-docker/buildDocker.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+echo "Make sure, that you've run 'gradle dist' on top directory first"
+
+echo "Unpacking distribution zip to target/dependency..."
+rm -rf app/target/dependency
+mkdir -p app/target/dependency && (cd app/target/dependency; unzip ../../../../borgbutler-server/build/distributions/borgbutler-server-*.zip)
+
+# Will be done by application after starting: (cd app; wget https://github.com/borgbackup/borg/releases/download/1.1.16/borg-linux64.tgz)
+
+echo "Building docker file..."
+(cd app; docker build -t kreinhard/borgbutler .)
+
+echo "Push: docker push kreinhard/boprgbutler:tagname"
+echo "Run with 'docker run -p 127.0.0.1:9042:9042 -v $HOME/.borgbutler:/Borgbutler kreinhard/borgbutler'"
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java
index 7c15849..2f288ff 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgInstallation.java
@@ -35,6 +35,7 @@
return;
}
}
+ borgVersion.setBinariesDownloadVersion(configuration.getBorgVersion());
initialize(getBinary(RunningMode.getOSType()));
if (version(configuration)) {
return;
@@ -95,7 +96,7 @@
String msg = null;
if (versionString != null) {
borgVersion.setVersion(versionString);
- int cmp = versionString.compareTo(borgVersion.getMinimumRequiredBorgVersion());
+ int cmp = BorgVersion.compareVersions(versionString, borgVersion.getMinimumRequiredBorgVersion());
if (cmp < 0) {
msg = "Found borg version '" + versionString + "' is less than minimum required version '" + borgVersion.getMinimumRequiredBorgVersion() + "'.";
log.info(msg);
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgVersion.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgVersion.java
index a134915..0f4c91f 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgVersion.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/BorgVersion.java
@@ -1,8 +1,14 @@
package de.micromata.borgbutler.server;
+import org.apache.commons.lang3.StringUtils;
+
public class BorgVersion {
- private String binariesDownloadVersion = "1.1.8";
- private String binariesDownloadUrl = "https://github.com/borgbackup/borg/releases/download/" + binariesDownloadVersion + "/";
+ public static final String BORG_DEFAULT_DOWNLOAD_VERSION = "1.1.16";
+
+ private static final String BORG_VERSION = BORG_DEFAULT_DOWNLOAD_VERSION;
+
+ private String binariesDownloadVersion = BORG_DEFAULT_DOWNLOAD_VERSION;
+
private String[][] borgBinaries = {
{"freebsd64", "FreeBSD 64"},
{"linux32", "Linux 32"},
@@ -11,6 +17,10 @@
private String minimumRequiredBorgVersion = "1.1.8";
+ public String getBinariesDownloadUrl() {
+ return "https://github.com/borgbackup/borg/releases/download/" + binariesDownloadVersion + "/";
+ }
+
/**
* One of the values "macosx64", "linux64" etc. for using a binary provided by BorgButler or null / "manual" for
* using a manual installed borg version.
@@ -33,14 +43,21 @@
return this.binariesDownloadVersion;
}
- public String getBinariesDownloadUrl() {
- return this.binariesDownloadUrl;
+ public void setBinariesDownloadVersion(String binariesDownloadVersion) {
+ if (StringUtils.isNotBlank(binariesDownloadVersion)) {
+ this.binariesDownloadVersion = binariesDownloadVersion;
+ } else {
+ this.binariesDownloadVersion = BORG_DEFAULT_DOWNLOAD_VERSION;
+ }
}
public String[][] getBorgBinaries() {
return this.borgBinaries;
}
+ /**
+ * @return The minimal required borg version (installed on host).
+ */
public String getMinimumRequiredBorgVersion() {
return this.minimumRequiredBorgVersion;
}
@@ -80,4 +97,32 @@
this.statusMessage = statusMessage;
return this;
}
+
+ public static int compareVersions(String thisVersion, String otherVersion) {
+ String[] thisParts = checkVersion(thisVersion);
+ String[] otherParts = checkVersion(otherVersion);
+ int length = Math.max(thisParts.length, otherParts.length);
+ for (int i = 0; i < length; i++) {
+ int thisPart = i < thisParts.length ?
+ Integer.parseInt(thisParts[i]) : 0;
+ int thatPart = i < otherParts.length ?
+ Integer.parseInt(otherParts[i]) : 0;
+ if (thisPart < thatPart)
+ return -1;
+ if (thisPart > thatPart)
+ return 1;
+ }
+ return 0;
+ }
+
+ // https://stackoverflow.com/questions/198431/how-do-you-compare-two-version-strings-in-java
+ public static String[] checkVersion(String version) {
+ if (version == null) {
+ throw new IllegalArgumentException("Version can not be null");
+ }
+ if (!version.matches("[0-9]+(\\.[0-9]+)*")) {
+ throw new IllegalArgumentException("Invalid version format: " + version);
+ }
+ return version.split("\\.");
+ }
}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
index 93f77ce..036d7fe 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/Main.java
@@ -54,6 +54,7 @@
options.addOption("p", "port", true, "The default port for the web server.");
options.addOption("q", "quiet", false, "Don't open browser automatically.");
options.addOption("h", "help", false, "Print this help screen.");
+ //options.addOption("homeDir", true, "Specify own home directory of butler. Default is $HOME/.borgbutler");
CommandLineParser parser = new DefaultParser();
try {
// parse the command line arguments
@@ -82,6 +83,10 @@
return;
}
}
+ String applicationHome = System.getProperty("borgbutlerHome");
+ if (applicationHome != null) {
+ ConfigurationHandler.init(applicationHome);
+ }
if (Desktop.isDesktopSupported()) {
RunningMode.setServerType(RunningMode.ServerType.DESKTOP);
} else {
@@ -104,6 +109,8 @@
} catch (Exception ex) {
log.info("Can't open web browser: " + ex.getMessage());
}
+ } else {
+ log.info("Please open your browser: " + server.getUrl().replace("0.0.0.0", "127.0.0.1")); // 0.0.0.0 for Docker installations.
}
} catch (ParseException ex) {
// oops, something went wrong
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/jetty/JettyServer.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/jetty/JettyServer.java
index 4f04b29..5f9c29c 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/jetty/JettyServer.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/jetty/JettyServer.java
@@ -29,12 +29,24 @@
import java.util.EnumSet;
public class JettyServer {
- private Logger log = LoggerFactory.getLogger(JettyServer.class);
- private static final String HOST = "127.0.0.1";
+ private static Logger log = LoggerFactory.getLogger(JettyServer.class);
+ private static String BIND_ADDRESS = "127.0.0.1";
private static final int MAX_PORT_NUMBER = 65535;
private Server server;
private int port;
+ static {
+ String bindAddress = System.getProperty("bindAddress");
+ if (bindAddress != null) {
+ BIND_ADDRESS = bindAddress;
+ }
+ log.info("Binding server to address: " + BIND_ADDRESS);
+ }
+
+ public static String getBindAddress() {
+ return BIND_ADDRESS;
+ }
+
public void start(String... restPackageNames) {
port = findFreePort();
if (port == -1) {
@@ -44,7 +56,7 @@
server = new Server();
ServerConnector connector = new ServerConnector(server);
- connector.setHost(HOST);
+ connector.setHost(BIND_ADDRESS);
connector.setPort(port);
server.setConnectors(new Connector[]{connector});
@@ -150,7 +162,7 @@
}
for (int i = port; i < port + 10; i++) {
try (ServerSocket socket = new ServerSocket()) {
- socket.bind(new InetSocketAddress(HOST, i));
+ socket.bind(new InetSocketAddress(BIND_ADDRESS, i));
return i;
} catch (Exception ex) {
log.info("Port " + i + " already in use or not available. Trying next port.");
@@ -170,7 +182,7 @@
}
public String getUrl() {
- return "http://" + HOST + ":" + port + "/";
+ return "http://" + BIND_ADDRESS + ":" + port + "/";
}
}
diff --git a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/user/UserFilter.java b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/user/UserFilter.java
index df4b45c..9e03d68 100644
--- a/borgbutler-server/src/main/java/de/micromata/borgbutler/server/user/UserFilter.java
+++ b/borgbutler-server/src/main/java/de/micromata/borgbutler/server/user/UserFilter.java
@@ -21,19 +21,7 @@
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- String remoteAddr = request.getRemoteAddr();
- if (remoteAddr == null || !remoteAddr.equals("127.0.0.1")) {
- log.warn("****************************************");
- log.warn("*********** **********");
- log.warn("*********** SECURITY WARNING! **********");
- log.warn("*********** **********");
- log.warn("*********** Externa access: **********");
- log.warn("*********** " + remoteAddr + " **********");
- log.warn("*********** **********");
- log.warn("****************************************");
- log.warn("Only access from local host yet supported due to security reasons.");
- throw new RuntimeException("Server is only available for localhost due to security reasons. A remote access is not yet available.");
- }
+ checkClientIp(request);
try {
UserData userData = UserUtils.getUser();
if (userData != null) {
@@ -63,4 +51,34 @@
public void destroy() {
}
+ private void checkClientIp(ServletRequest request) {
+ String remoteAddr = request.getRemoteAddr();
+ boolean allowed = false;
+ String allowedClientIps = System.getProperty("allowedClientIps");
+ if (remoteAddr != null) {
+ if (remoteAddr.equals("127.0.0.1")) {
+ allowed = true;
+ } else {
+ if (allowedClientIps != null && remoteAddr.startsWith(allowedClientIps)) {
+ allowed = true;
+ }
+ }
+ }
+ if (!allowed) {
+ log.warn("****************************************");
+ log.warn("*********** **********");
+ log.warn("*********** SECURITY WARNING! **********");
+ log.warn("*********** **********");
+ log.warn("*********** Externa access: **********");
+ log.warn("*********** " + remoteAddr + " **********");
+ log.warn("*********** **********");
+ log.warn("****************************************");
+ if (allowedClientIps == null) {
+ log.warn("Only access from local host yet supported due to security reasons. You may configure client address ranges by -DallowedClientIps=172.17.0.1 or -DallowedClientIps=172.17.");
+ } else {
+ log.warn("Only access from local host and " + allowedClientIps + " (option -DallowedClientIps) yet supported due to security reasons.");
+ }
+ throw new RuntimeException("Server is only available for localhost due to security reasons. A remote access is not yet available.");
+ }
+ }
}
diff --git a/borgbutler-server/src/main/resources/log4j.properties b/borgbutler-server/src/main/resources/log4j.properties
index 03a0e14..ee7031b 100644
--- a/borgbutler-server/src/main/resources/log4j.properties
+++ b/borgbutler-server/src/main/resources/log4j.properties
@@ -14,7 +14,7 @@
log4j.appender.file=org.apache.log4j.RollingFileAppender
-log4j.appender.file.File=borgbutler.log
+log4j.appender.file.File=${borgbutlerHome}borgbutler.log
log4j.appender.file.MaxFileSize=10MB
log4j.appender.file.MaxBackupIndex=5
log4j.appender.file.layout=org.apache.log4j.PatternLayout
diff --git a/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgVersionTest.java b/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgVersionTest.java
new file mode 100644
index 0000000..0d233c7
--- /dev/null
+++ b/borgbutler-server/src/test/java/de/micromata/borgbutler/server/BorgVersionTest.java
@@ -0,0 +1,20 @@
+package de.micromata.borgbutler.server;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class BorgVersionTest {
+
+ @Test
+ void versionCompareTest() {
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ BorgVersion.compareVersions(null, "");
+ });
+ Assertions.assertThrows(IllegalArgumentException.class, () -> {
+ BorgVersion.compareVersions("", "");
+ });
+ Assertions.assertEquals(-1, BorgVersion.compareVersions("1.1.8", "1.1.16"));
+ Assertions.assertEquals(0, BorgVersion.compareVersions("1.1.8", "1.1.8"));
+ Assertions.assertEquals(1, BorgVersion.compareVersions("1.1.16", "1.1.8"));
+ }
+}
diff --git a/build.gradle b/build.gradle
index 5c6fc0f..d92fa1f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,7 +10,7 @@
apply plugin: 'maven'
group = 'de.micromata.borgbutler'
- version = '0.2-SNAPSHOT'
+ version = '0.3-SNAPSHOT'
}
subprojects {
--
Gitblit v1.10.0