diff --git a/Dockerfile b/Dockerfile index c0c9041..ebdab25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,4 +14,5 @@ ENV SQLITE_DATABASE_PATH="/var/mxisd/mxisd.db" CMD [ "/start.sh" ] ADD src/docker/start.sh /start.sh -ADD build/libs/mxisd.jar /mxisd.jar +ADD src/script/mxisd /app/mxisd +ADD build/libs/mxisd.jar /app/mxisd.jar diff --git a/build.gradle b/build.gradle index 13e3c4e..ba8f139 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ apply plugin: 'application' apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'idea' -def confFileName = "application.example.yaml" +def confFileName = "mxisd.example.yaml" def distDir = "${project.buildDir}/dist" def debBinPath = "/usr/lib/mxisd" @@ -33,7 +33,8 @@ def debConfPath = "/etc/mxisd" def debDataPath = "/var/lib/mxisd" def debSystemdPath = "/etc/systemd/system" -def debConfFileName = "mxisd-sample.yaml" +def debConfFileName = confFileName +def debStartScriptFilename = "mxisd" def debBuildBasePath = "${project.buildDir}/tmp/debian" def debBuildDebianPath = "${debBuildBasePath}/DEBIAN" @@ -115,8 +116,8 @@ dependencies { compile 'com.googlecode.libphonenumber:libphonenumber:8.7.1' // E-mail sending - compile 'com.sun.mail:javax.mail:1.6.2' compile 'javax.mail:javax.mail-api:1.6.2' + compile 'com.sun.mail:javax.mail:1.6.2' // Google Firebase Authentication backend compile 'com.google.firebase:firebase-admin:5.3.0' @@ -163,7 +164,7 @@ task debBuild(dependsOn: shadowJar) { println "Version for package: ${debVersion}" mkdir distDir mkdir debBuildBasePath - mkdir "${debBuildBasePath}/DEBIAN" + mkdir debBuildDebianPath mkdir debBuildBinPath mkdir debBuildConfPath mkdir debBuildDataPath @@ -174,10 +175,10 @@ task debBuild(dependsOn: shadowJar) { into debBuildBinPath } - ant.chmod( - file: "${debBuildBinPath}/mxisd.jar", - perm: 'a+x' - ) + copy { + from "${project.file("src/script/" + debStartScriptFilename)}" + into debBuildBinPath + } copy { from(project.file(confFileName)) { @@ -188,14 +189,14 @@ task debBuild(dependsOn: shadowJar) { ant.replaceregexp( // FIXME adapt to new config format file: "${debBuildConfPath}/${debConfFileName}", - match: "key.path:(.*)", - replace: "key.path: '${debDataPath}/signing.key'" + match: "key:\\R path:(.*)", + replace: "key:\n path: '${debDataPath}/signing.key'" ) ant.replaceregexp( // FIXME adapt to new config format file: "${debBuildConfPath}/${debConfFileName}", - match: "storage.provider.sqlite.database:(.*)", - replace: "storage.provider.sqlite.database: '${debDataPath}/mxisd.db'" + match: "storage:\\R provider:\\R sqlite:\\R database:(.*)", + replace: "storage:\n provider:\n sqlite:\n database: '${debDataPath}/mxisd.db'" ) copy { diff --git a/docs/build.md b/docs/build.md index 5ee2f25..0a6b155 100644 --- a/docs/build.md +++ b/docs/build.md @@ -17,9 +17,8 @@ cd mxisd ./gradlew build ``` -Create a new configuration file by coping `application.example.yaml` to `application.yaml` and edit to your needs. -For advanced configuration, see the [Configure section](configure.md). -**NOTE**: `application.yaml` is also called `mxisd.yaml` in some specific installations. +Create a new configuration file by coping `mxisd.example.yaml` to `mxisd.yaml` and edit to your needs. +For advanced configuration, see the [Configure section](configure.md). Start the server in foreground to validate the build and configuration: ```bash @@ -59,7 +58,7 @@ Requirements: [Build mxisd](#build) then: ```bash -./gradlew buildDeb +./gradlew debBuild ``` You will find the debian package in `build/dist`. Then follow the instruction in the [Debian package](install/debian.md) document. @@ -72,4 +71,4 @@ Then follow the instruction in the [Debian package](install/debian.md) document. Then follow the instructions in the [Docker install](install/docker.md#configure) document. ## Next steps -- [Integrate with your infrastructure](getting-started.md#integrate) \ No newline at end of file +- [Integrate with your infrastructure](getting-started.md#integrate) diff --git a/docs/install/source.md b/docs/install/source.md index bf6068c..a46b190 100644 --- a/docs/install/source.md +++ b/docs/install/source.md @@ -2,37 +2,43 @@ ## Instructions Follow the [build instructions](../build.md) then: -1. Prepare files and directories: +### Prepare files and directories: ```bash # Create a dedicated user useradd -r mxisd -# Create bin directory -mkdir /opt/mxisd - # Create config directory and set ownership -mkdir -p /etc/opt/mxisd -chown -R mxisd /etc/opt/mxisd +mkdir -p /etc/mxisd # Create data directory and set ownership -mkdir -p /var/opt/mxisd -chown -R mxisd /var/opt/mxisd +mkdir -p /var/lib/mxisd +chown -R mxisd /var/lib/mxisd -# Copy /build/libs/mxisd.jar to bin directory -cp ./build/libs/mxisd.jar /opt/mxisd/ -chown mxisd /opt/mxisd/mxisd.jar -chmod a+x /opt/mxisd/mxisd.jar +# Create bin directory, copy the jar and launch scriot to bin directory +mkdir /usr/lib/mxisd +cp ./build/libs/mxisd.jar /usr/lib/mxisd/ +cp ./src/script/mxisd /usr/lib/mxisd +chown -R mxisd /usr/lib/mxisd +chmod a+x /usr/lib/mxisd/mxisd # Create symlink for easy exec -ln -s /opt/mxisd/mxisd.jar /usr/bin/mxisd +ln -s /usr/lib/mxisd/mxisd /usr/bin/mxisd ``` -2. Copy the sample config file `./mxisd.example.yaml` to `/etc/opt/mxisd/mxisd.yaml`, edit to your needs -3. Copy `src/systemd/mxisd.service` to `/etc/systemd/system/` and edit if needed -4. Enable service for auto-startup + +### Prepare config file +Copy the sample config file `./mxisd.example.yaml` to `/etc/mxisd/mxisd.yaml`, edit to your needs + +### Prepare Systemd +1. Copy `src/systemd/mxisd.service` to `/etc/systemd/system/` and edit if needed +2. Enable service for auto-startup ```bash systemctl enable mxisd ``` -5. Start mxisd + +### Run ```bash systemctl start mxisd ``` + +## Debug +mxisd logs to stdout, which is normally sent to `/var/log/syslog` or `/var/log/messages`. diff --git a/mxisd.example.yaml b/mxisd.example.yaml index ec427a6..d058a48 100644 --- a/mxisd.example.yaml +++ b/mxisd.example.yaml @@ -1,14 +1,14 @@ # Sample configuration file explaining the minimum required keys to be set to run mxisd # -# For a complete list of options, see https://github.com/kamax-matrix/mxisd +# For a complete list of options, see https://github.com/kamax-matrix/mxisd/docs/README.md ####################### # Matrix config items # ####################### # Matrix domain, same as the domain configure in your Homeserver configuration. -# (note: in Synapse Homeserver, the Matrix domain may be defined as 'server_name' in configuration file). +# NOTE: in Synapse Homeserver, the Matrix domain is defined as 'server_name' in configuration file. # -# This is used to build the various identifiers for identity, auth and directory. +# This is used to build the various identifiers in all the features. matrix: domain: '' @@ -17,29 +17,20 @@ matrix: # Signing keys # ################ # Absolute path for the Identity Server signing key. -# During testing, /var/tmp/mxisd.key is a possible value +# This is **NOT** your homeserver key. +# The signing key is auto-generated during execution time if not present. # +# During testing, /var/tmp/mxisd.key is a possible value # For production, recommended location shall be one of the following: # - /var/opt/mxisd/sign.key # - /var/local/mxisd/sign.key # - /var/lib/mxisd/sign.key # -# The signing key is auto-generated during execution time if not present. key: path: '' -############################ -# Persistence config items # -############################ - -# Configure the storage backend, usually a DB -# Possible built-in values: -# sqlite SQLite backend, default -# -#storage.backend: 'sqlite' - -# Path to the SQLite DB file +# Path to the SQLite DB file for mxisd internal storage # # Examples: # - /var/opt/mxisd/mxisd.db @@ -57,7 +48,7 @@ storage: #################### # # Root/Central servers to be used as final fallback when performing lookups. -# By default, for privacy reasons, matrix.org servers are not enabled anymore. +# By default, for privacy reasons, matrix.org servers are not enabled. # See the following issue: https://github.com/kamax-matrix/mxisd/issues/76 # # If you would like to use them and trade away your privacy for convenience, uncomment the following option: @@ -103,7 +94,6 @@ threepid: connectors: smtp: - # SMTP host host: "smtp.example.org" @@ -117,7 +107,7 @@ threepid: # 1 Enable TLS if supported by server (default) # 2 Force TLS and fail if not available # - # tls: 1 + tls: 1 # Login for SMTP login: "matrix-identity@example.org" diff --git a/src/debian/postinst b/src/debian/postinst index 4b1c5ad..7b06340 100755 --- a/src/debian/postinst +++ b/src/debian/postinst @@ -6,8 +6,8 @@ useradd -r mxisd || true # Set permissions for data directory chown -R mxisd:mxisd %DEB_DATA_DIR% -# Create symlink to mxusd -ln -sfT /usr/lib/mxisd/mxisd.jar /usr/bin/mxisd +# Create symlink to mxisd run script +ln -sfT /usr/lib/mxisd/mxisd /usr/bin/mxisd # Enable systemd service systemctl enable mxisd.service diff --git a/src/docker/start.sh b/src/docker/start.sh index 0d7acf5..37daba6 100755 --- a/src/docker/start.sh +++ b/src/docker/start.sh @@ -1,25 +1,34 @@ -#!/usr/bin/env bash +#!/bin/bash + if [[ -n "$CONF_FILE_PATH" ]] && [ ! -f "$CONF_FILE_PATH" ]; then echo "Generating config file $CONF_FILE_PATH" touch "CONF_FILE_PATH" if [[ -n "$MATRIX_DOMAIN" ]]; then echo "Setting matrix domain to $MATRIX_DOMAIN" - echo "matrix.domain: $MATRIX_DOMAIN" >> "$CONF_FILE_PATH" + echo "matrix:" >> "$CONF_FILE_PATH" + echo " domain: '$MATRIX_DOMAIN'" >> "$CONF_FILE_PATH" + echo >> "$CONF_FILE_PATH" fi if [[ -n "$SIGN_KEY_PATH" ]]; then echo "Setting signing key path to $SIGN_KEY_PATH" - echo "key.path: $SIGN_KEY_PATH" >> "$CONF_FILE_PATH" + echo "key:" >> "$CONF_FILE_PATH" + echo " path: '$SIGN_KEY_PATH'" >> "$CONF_FILE_PATH" + echo >> "$CONF_FILE_PATH" fi if [[ -n "$SQLITE_DATABASE_PATH" ]]; then echo "Setting SQLite DB path to $SQLITE_DATABASE_PATH" - echo "storage.provider.sqlite.database: $SQLITE_DATABASE_PATH" >> "$CONF_FILE_PATH" + echo "storage:" >> "$CONF_FILE_PATH" + echo " provider:" >> "$CONF_FILE_PATH" + echo " sqlite:" >> "$CONF_FILE_PATH" + echo " database: '$SQLITE_DATABASE_PATH'" >> "$CONF_FILE_PATH" + echo >> "$CONF_FILE_PATH" fi echo "Starting mxisd..." echo fi -exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /mxisd.jar +exec java -jar /app/mxisd.jar -c /etc/mxisd/mxisd.yaml diff --git a/src/main/java/io/kamax/mxisd/MxisdStandaloneExec.java b/src/main/java/io/kamax/mxisd/MxisdStandaloneExec.java index 826966b..42b5c25 100644 --- a/src/main/java/io/kamax/mxisd/MxisdStandaloneExec.java +++ b/src/main/java/io/kamax/mxisd/MxisdStandaloneExec.java @@ -22,19 +22,48 @@ package io.kamax.mxisd; import io.kamax.mxisd.config.MxisdConfig; import io.kamax.mxisd.config.YamlConfigLoader; +import org.apache.commons.lang3.StringUtils; import java.io.IOException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Objects; public class MxisdStandaloneExec { public static void main(String[] args) throws IOException { - // FIXME no hard-coding, make it configurable via Build, Env and CLI parameters - MxisdConfig cfg = YamlConfigLoader.loadFromFile("mxisd.yaml"); - HttpMxisd mxisd = new HttpMxisd(cfg); + MxisdConfig cfg = null; - Runtime.getRuntime().addShutdownHook(new Thread(mxisd::stop)); + Iterator argsIt = Arrays.asList(args).iterator(); + while (argsIt.hasNext()) { + String arg = argsIt.next(); + if (StringUtils.equals("-c", arg)) { + String cfgFile = argsIt.next(); + cfg = YamlConfigLoader.loadFromFile(cfgFile); + System.out.println("Loaded configuration from " + cfgFile); + } else { + System.out.println("Invalid argument: " + arg); + System.exit(1); + } + } - mxisd.start(); + if (Objects.isNull(cfg)) { + cfg = YamlConfigLoader.tryLoadFromFile("mxisd.yaml").orElseGet(MxisdConfig::new); + } + + try { + HttpMxisd mxisd = new HttpMxisd(cfg); + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + mxisd.stop(); + System.out.println("------------- mxisd stopped -------------"); + })); + mxisd.start(); + + System.out.println("------------- mxisd started -------------"); + } catch (Throwable t) { + t.printStackTrace(); + System.exit(1); + } } } diff --git a/src/main/java/io/kamax/mxisd/config/YamlConfigLoader.java b/src/main/java/io/kamax/mxisd/config/YamlConfigLoader.java index 70e4a09..650613a 100644 --- a/src/main/java/io/kamax/mxisd/config/YamlConfigLoader.java +++ b/src/main/java/io/kamax/mxisd/config/YamlConfigLoader.java @@ -26,7 +26,9 @@ import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.representer.Representer; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.util.Optional; public class YamlConfigLoader { @@ -39,4 +41,14 @@ public class YamlConfigLoader { return GsonUtil.get().fromJson(GsonUtil.get().toJson(o), MxisdConfig.class); } + public static Optional tryLoadFromFile(String path) { + try { + return Optional.of(loadFromFile(path)); + } catch (FileNotFoundException e) { + return Optional.empty(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } diff --git a/src/script/mxisd b/src/script/mxisd new file mode 100755 index 0000000..331afe1 --- /dev/null +++ b/src/script/mxisd @@ -0,0 +1,168 @@ +#!/usr/bin/env sh + +############################################################################## +## +## mxisd start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done + +APP_HOME=`dirname "$PRG"` +APP_NAME="mxisd" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and MXISD_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/mxisd.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +for s in "${@}" ; do + s=\"$s\" + APP_ARGS=$APP_ARGS" "$s +done + +# Collect JVM options +JVM_OPTS=$DEFAULT_JVM_OPTS" "$JAVA_OPTS" "$MXISD_OPTS + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +eval \"$JAVACMD\" $JVM_OPTS -jar \"$CLASSPATH\" $APP_ARGS diff --git a/src/systemd/mxisd.service b/src/systemd/mxisd.service index fa21acb..e60803f 100644 --- a/src/systemd/mxisd.service +++ b/src/systemd/mxisd.service @@ -4,8 +4,7 @@ After=syslog.target [Service] User=mxisd -ExecStart=/usr/bin/mxisd --spring.config.location=/etc/mxisd/ --spring.config.name=mxisd --spring.profiles.active=systemd -SuccessExitStatus=143 +ExecStart=/usr/bin/mxisd -c /etc/mxisd/mxisd.yaml [Install] WantedBy=multi-user.target