From cf5d194b1444ad8a3ba8a3549375af5a5a4d42fb Mon Sep 17 00:00:00 2001 From: Geoff Bourne Date: Sat, 23 Apr 2016 22:23:55 -0500 Subject: [PATCH] [mc] Robust handling of Forge, Bukkit, and Spigot version selection * refactor server.properties sed ops into a utility function * also switch to jq instead of jsawk * simplify to BUILD_FROM_SOURCE from BUILD_SPIGOT_FROM_SOURCE Fixes #70 --- minecraft-server/Dockerfile | 7 +- minecraft-server/README.md | 24 +-- minecraft-server/start-minecraft.sh | 254 +++++++++------------------- minecraft-server/start.sh | 7 +- 4 files changed, 100 insertions(+), 192 deletions(-) diff --git a/minecraft-server/Dockerfile b/minecraft-server/Dockerfile index 8b8aabac..5b827eef 100644 --- a/minecraft-server/Dockerfile +++ b/minecraft-server/Dockerfile @@ -2,21 +2,18 @@ FROM java:8 MAINTAINER itzg -ENV APT_GET_UPDATE 2015-10-03 +ENV APT_GET_UPDATE 2016-04-23 RUN apt-get update RUN DEBIAN_FRONTEND=noninteractive apt-get install -y \ - libmozjs-24-bin \ imagemagick \ lsof \ nano \ sudo \ vim \ + jq \ && apt-get clean -RUN update-alternatives --install /usr/bin/js js /usr/bin/js24 100 -RUN wget -O /usr/bin/jsawk https://github.com/micha/jsawk/raw/master/jsawk -RUN chmod +x /usr/bin/jsawk RUN useradd -M -s /bin/false --uid 1000 minecraft \ && mkdir /data \ && mkdir /config \ diff --git a/minecraft-server/README.md b/minecraft-server/README.md index 639749b2..57c9eaed 100644 --- a/minecraft-server/README.md +++ b/minecraft-server/README.md @@ -147,7 +147,7 @@ There are two additional volumes that can be mounted; `/mods` and `/config`. Any files in either of these filesystems will be copied over to the main `/data` filesystem before starting Minecraft. -This works well if you want to have a common set of modules in a separate +This works well if you want to have a common set of modules in a separate location, but still have multiple worlds with different server requirements in either persistent volumes or a downloadable archive. @@ -164,7 +164,7 @@ available. The latest build in this branch will be used. You can install Bukkit plugins in two ways. -You can build spigot from source by adding `-e BUILD_SPIGOT_FROM_SOURCE=true` +You can build spigot from source by adding `-e BUILD_FROM_SOURCE=true` ### Using the /data volume @@ -200,7 +200,7 @@ There is one additional volume that can be mounted; `/plugins`. Any files in this filesystem will be copied over to the main `/data/plugins` filesystem before starting Minecraft. -This works well if you want to have a common set of plugins in a separate +This works well if you want to have a common set of plugins in a separate location, but still have multiple worlds with different server requirements in either persistent volumes or a downloadable archive. @@ -274,7 +274,7 @@ To use rcon use the `ENABLE_RCON` and `RCON_PASSORD` variables. By default rcon port will be `25575` but can easily be changed with the `RCON_PORT` variable. docker run -d -e ENABLE_RCON=true -e RCON_PASSWORD=testing - + ### Query Enabling this will enable the gamespy query protocol. @@ -286,13 +286,13 @@ By default the query port will be `25565` (UDP) but can easily be changed with t ### Max players By default max players is 20, you can increase this with the `MAX_PLAYERS` variable. - + docker run -d -e MAX_PLAYERS=50 - - + + ### Max world size -This sets the maximum possible size in blocks, expressed as a radius, that the world border can obtain. +This sets the maximum possible size in blocks, expressed as a radius, that the world border can obtain. docker run -d -e MAX_WORLD_SIZE=10000 @@ -338,7 +338,7 @@ If set to true, players will be set to spectator mode if they die. ### Max Build Height -The maximum height in which building is allowed. +The maximum height in which building is allowed. Terrain may still naturally generate above a low height limit. docker run -d -e MAX_BUILD_HEIGHT=256 @@ -370,7 +370,7 @@ Determines if villagers will be spawned. ### View Distance Sets the amount of world data the server sends the client, measured in chunks in each direction of the player (radius, not diameter). -It determines the server-side viewing distance. +It determines the server-side viewing distance. docker run -d -e VIEW_DISTANCE=10 @@ -448,7 +448,7 @@ where the default is "world": Instead of mounting the `/data` volume, you can instead specify the URL of a ZIP file containing an archived world. This will be downloaded, and unpacked in the `/data` directory; if it does not contain a subdirectory -called `world/` then it will be searched for a file `level.dat` and the +called `world/` then it will be searched for a file `level.dat` and the containing subdirectory renamed to `world`. This means that most of the archived Minecraft worlds downloadable from the Internet will already be in the correct format. @@ -468,7 +468,7 @@ name of a linked container. ### Downloadable mod/plugin pack for Forge, Bukkit, and Spigot Servers Like the `WORLD` option above, you can specify the URL of a "mod pack" -to download and install into `mods` for Forge or `plugins` for Bukkit/Spigot. +to download and install into `mods` for Forge or `plugins` for Bukkit/Spigot. To use this option pass the environment variable `MODPACK`, such as docker run -d -e MODPACK=http://www.example.com/mods/modpack.zip ... diff --git a/minecraft-server/start-minecraft.sh b/minecraft-server/start-minecraft.sh index 2fa393a8..8e44f85a 100755 --- a/minecraft-server/start-minecraft.sh +++ b/minecraft-server/start-minecraft.sh @@ -21,16 +21,16 @@ fi echo "Checking version information." case "X$VERSION" in X|XLATEST|Xlatest) - VANILLA_VERSION=`wget -O - https://s3.amazonaws.com/Minecraft.Download/versions/versions.json | jsawk -n 'out(this.latest.release)'` + VANILLA_VERSION=`curl -sSL https://s3.amazonaws.com/Minecraft.Download/versions/versions.json | jq -r '.latest.release'` ;; XSNAPSHOT|Xsnapshot) - VANILLA_VERSION=`wget -O - https://s3.amazonaws.com/Minecraft.Download/versions/versions.json | jsawk -n 'out(this.latest.snapshot)'` + VANILLA_VERSION=`curl -sSL https://s3.amazonaws.com/Minecraft.Download/versions/versions.json | jq -r '.latest.snapshot'` ;; X[1-9]*) VANILLA_VERSION=$VERSION ;; *) - VANILLA_VERSION=`wget -O - https://s3.amazonaws.com/Minecraft.Download/versions/versions.json | jsawk -n 'out(this.latest.release)'` + VANILLA_VERSION=`curl -sSL https://s3.amazonaws.com/Minecraft.Download/versions/versions.json | jq -r '.latest.release'` ;; esac @@ -39,53 +39,18 @@ cd /data echo "Checking type information." case "$TYPE" in *BUKKIT|*bukkit|SPIGOT|spigot) - TYPE=SPIGOT - if [ -z "$BUILD_SPIGOT_FROM_SOURCE" ]; then - case "$TYPE" in - *BUKKIT|*bukkit) - echo "Downloading latest CraftBukkit $VANILLA_VERSION server ..." - SERVER=craftbukkit_server.jar - ;; - *) - echo "Downloading latest Spigot $VANILLA_VERSION server ..." - SERVER=spigot_server.jar - ;; - esac - case $VANILLA_VERSION in - 1.8*) - URL=/spigot18/$SERVER - ;; - 1.9*) - URL=/spigot19/$SERVER - ;; - *) - echo "That version of $SERVER is not available." - exit 1 - ;; - esac - - #attempt https, and if it fails, fallback to http and download that way. Display error if neither works. - wget -q -N $SERVER https://getspigot.org$URL || \ - (echo "Falling back to http, unable to contact server using https..." && \ - wget -q -N $SERVER http://getspigot.org$URL) || \ - echo "Unable to download new copy of spigot server" - fi - if [ "$BUILD_SPIGOT_FROM_SOURCE" = true ]; then - echo "Building spigot from source, might take a while, get some coffee" + if [[ "$BUILD_SPIGOT_FROM_SOURCE" = TRUE || "$BUILD_SPIGOT_FROM_SOURCE" = true || "$BUILD_FROM_SOURCE" = TRUE || "$BUILD_FROM_SOURCE" = true ]]; then if [ ! -f /data/spigot_server.jar ]; then - echo "Downloading and building buildtools for version $VANILLA_VERSION" + echo "Building Spigot $VANILLA_VERSION from source, might take a while, get some coffee" mkdir /data/temp cd /data/temp - wget -P /data/temp https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar && \ - java -jar /data/temp/BuildTools.jar --rev $VANILLA_VERSION && \ - find * -maxdepth 0 ! -name '*.jar' -exec rm -rf {} \; && \ - chown minecraft:minecraft spigot-*.jar && \ - chown minecraft:minecraft craftbukkit-*.jar && \ - mv spigot-*.jar /data/spigot_server.jar && \ + wget -q -P /data/temp https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar && \ + java -jar /data/temp/BuildTools.jar --rev $VANILLA_VERSION 2>&1 |tee /data/spigot_build.log| while read l; do echo -n .; done; echo "done" + mv spigot-*.jar /data/spigot_server.jar mv craftbukkit-*.jar /data/craftbukkit_server.jar echo "Cleaning up" rm -rf /data/temp - cd /data + cd /data fi case "$TYPE" in *BUKKIT|*bukkit) @@ -95,7 +60,29 @@ case "$TYPE" in SERVER=spigot_server.jar ;; esac - fi + else + case "$TYPE" in + *BUKKIT|*bukkit) + match="Craftbukkit $VANILLA_VERSION" + SERVER=craftbukkit.jar + ;; + *) + match="Spigot $VANILLA_VERSION" + SERVER=spigot.jar + ;; + esac + + curl -o /tmp/versions -sSL https://getspigot.org/api/getversions + downloadUrl=$(cat /tmp/versions | jq -r ".[] | select(.version == \"$match\") | .downloadUrl") + if [[ -n $downloadUrl ]]; then + echo "Downloading $match" + curl -o $SERVER -sSL "$downloadUrl" + else + echo "ERROR: Version $VANILLA_VERSION is not supported for $TYPE" + echo " Refer to http://getspigot.org for supported versions" + exit 2 + fi + fi ;; FORGE|forge) @@ -104,12 +91,21 @@ case "$TYPE" in echo "Checking Forge version information." case $FORGEVERSION in - RECOMMENDED) - FORGE_VERSION=`wget -O - http://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json | jsawk -n "out(this.promos['$norm-recommended'])"` + RECOMMENDED) + curl -o /tmp/forge.json -sSL http://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json + FORGE_VERSION=$(cat /tmp/forge.json | jq -r ".promos[\"$norm-recommended\"]") + if [ $FORGE_VERSION = null ]; then + FORGE_VERSION=$(cat /tmp/forge.json | jq -r ".promos[\"$norm-latest\"]") + if [ $FORGE_VERSION = null ]; then + echo "ERROR: Version $FORGE_VERSION is not supported by Forge" + echo " Refer to http://files.minecraftforge.net/ for supported versions" + exit 2 + fi + fi ;; - *) - FORGE_VERSION=$FORGEVERSION + *) + FORGE_VERSION=$FORGEVERSION ;; esac @@ -151,10 +147,6 @@ case "$TYPE" in esac -#Switch to minecraft user -echo "...switching to user 'minecraft'" -su - minecraft - # If supplied with a URL for a world, download it and unpack if [[ "$WORLD" ]]; then case "X$WORLD" in @@ -210,6 +202,16 @@ case "X$MODPACK" in esac fi +function setServerProp { + local prop=$1 + local var=$2 + if [ -n "$var" ]; then + echo "Setting $prop to $var" + sed -i "/$prop\s*=/ c $prop=$var" /data/server.properties + fi + +} + if [ ! -e server.properties ]; then echo "Creating server.properties" cp /tmp/server.properties . @@ -220,122 +222,31 @@ if [ ! -e server.properties ]; then sed -i "/white-list\s*=/ c white-list=true" /data/server.properties fi - if [ -n "$MOTD" ]; then - echo "Setting motd" - sed -i "/motd\s*=/ c motd=$MOTD" /data/server.properties - fi - - if [ -n "$ALLOW_NETHER" ]; then - echo "Setting allow-nether" - sed -i "/allow-nether\s*=/ c allow-nether=$ALLOW_NETHER" /data/server.properties - fi - - if [ -n "$ANNOUNCE_PLAYER_ACHIEVEMENTS" ]; then - echo "Setting announce-player-achievements" - sed -i "/announce-player-achievements\s*=/ c announce-player-achievements=$ANNOUNCE_PLAYER_ACHIEVEMENTS" /data/server.properties - fi - - if [ -n "$ENABLE_COMMAND_BLOCK" ]; then - echo "Setting enable-command-block" - sed -i "/enable-command-block\s*=/ c enable-command-block=$ENABLE_COMMAND_BLOCK" /data/server.properties - fi - - if [ -n "$SPAWN_ANIMAILS" ]; then - echo "Setting spawn-animals" - sed -i "/spawn-animals\s*=/ c spawn-animals=$SPAWN_ANIMAILS" /data/server.properties - fi - - - if [ -n "$SPAWN_MONSTERS" ]; then - echo "Setting spawn-monsters" - sed -i "/spawn-monsters\s*=/ c spawn-monsters=$SPAWN_MONSTERS" /data/server.properties - fi - - if [ -n "$SPAWN_NPCS" ]; then - echo "Setting spawn-npcs" - sed -i "/spawn-npcs\s*=/ c spawn-npcs=$SPAWN_NPCS" /data/server.properties - fi - - - if [ -n "$GENERATE_STRUCTURES" ]; then - echo "Setting generate-structures" - sed -i "/generate-structures\s*=/ c generate-structures=$GENERATE_STRUCTURES" /data/server.properties - fi - - if [ -n "$VIEW_DISTANCE" ]; then - echo "Setting view-distance" - sed -i "/view-distance\s*=/ c view-distance=$VIEW_DISTANCE" /data/server.properties - fi - - if [ -n "$HARDCORE" ]; then - echo "Setting hardcore" - sed -i "/hardcore\s*=/ c hardcore=$HARDCORE" /data/server.properties - fi - - if [ -n "$MAX_BUILD_HEIGHT" ]; then - echo "Setting max-build-height" - sed -i "/max-build-height\s*=/ c max-build-height=$MAX_BUILD_HEIGHT" /data/server.properties - fi - - if [ -n "$FORCE_GAMEMODE" ]; then - echo "Setting force-gamemode" - sed -i "/force-gamemode\s*=/ c force-gamemode=$FORCE_GAMEMODE" /data/server.properties - fi - - if [ -n "$MAX_TICK_TIME" ]; then - echo "Setting max-tick-time" - sed -i "/max-tick-time\s*=/ c max-tick-time=$MAX_TICK_TIME" /data/server.properties - fi - - if [ -n "$ENABLE_QUERY" ]; then - echo "Enabling query" - sed -i "/enable-query\s*=/ c enable-query=$ENABLE_QUERY" /data/server.properties - fi - - if [ -n "$QUERY_PORT" ]; then - echo "Setting query port" - sed -i "/query.port\s*=/ c query.port=$QUERY_PORT" /data/server.properties - fi - - if [ -n "$ENABLE_RCON" ]; then - echo "Enabling rcon" - sed -i "/enable-rcon\s*=/ c enable-rcon=$ENABLE_RCON" /data/server.properties - fi - - if [ -n "$RCON_PASSWORD" ]; then - echo "Setting rcon password to $RCON_PASSWORD" - sed -i "/rcon.password\s*=/ c rcon.password=$RCON_PASSWORD" /data/server.properties - fi - - if [ -n "$RCON_PORT" ]; then - echo "Setting rcon port" - sed -i "/rcon.port\s*=/ c rcon.port=$RCON_PORT" /data/server.properties - fi - - if [ -n "$MAX_PLAYERS" ]; then - echo "Setting max players" - sed -i "/max-players\s*=/ c max-players=$MAX_PLAYERS" /data/server.properties - fi - - if [ -n "$MAX_WORLD_SIZE" ]; then - echo "Setting max world size" - sed -i "/max-world-size\s*=/ c max-world-size=$MAX_WORLD_SIZE" /data/server.properties - fi - - if [ -n "$LEVEL" ]; then - echo "Setting level name" - sed -i "/level-name\s*=/ c level-name=$LEVEL" /data/server.properties - fi - - if [ -n "$SEED" ]; then - echo "Setting seed" - sed -i "/level-seed\s*=/ c level-seed=$SEED" /data/server.properties - fi - - if [ -n "$PVP" ]; then - echo "Setting PVP" - sed -i "/pvp\s*=/ c pvp=$PVP" /data/server.properties - fi + setServerProp "motd" "$MOTD" + setServerProp "allow-nether" "$ALLOW_NETHER" + setServerProp "announce-player-achievements" "$ANNOUNCE_PLAYER_ACHIEVEMENTS" + setServerProp "enable-command-block" "$ENABLE_COMMAND_BLOCK" + setServerProp "spawn-animals" "$SPAWN_ANIMAILS" + setServerProp "spawn-monsters" "$SPAWN_MONSTERS" + setServerProp "spawn-npcs" "$SPAWN_NPCS" + setServerProp "generate-structures" "$GENERATE_STRUCTURES" + setServerProp "spawn-npcs" "$SPAWN_NPCS" + setServerProp "view-distance" "$VIEW_DISTANCE" + setServerProp "hardcore" "$HARDCORE" + setServerProp "max-build-height" "$MAX_BUILD_HEIGHT" + setServerProp "force-gamemode" "$FORCE_GAMEMODE" + setServerProp "hardmax-tick-timecore" "$MAX_TICK_TIME" + setServerProp "enable-query" "$ENABLE_QUERY" + setServerProp "query.port" "$QUERY_PORT" + setServerProp "enable-rcon" "$ENABLE_RCON" + setServerProp "rcon.password" "$RCON_PASSWORD" + setServerProp "rcon.port" "$RCON_PORT" + setServerProp "max-players" "$MAX_PLAYERS" + setServerProp "max-world-size" "$MAX_WORLD_SIZE" + setServerProp "level-name" "$LEVEL" + setServerProp "level-seed" "$SEED" + setServerProp "pvp" "$PVP" + setServerProp "generator-settings" "$GENERATOR_SETTINGS" if [ -n "$LEVEL_TYPE" ]; then # normalize to uppercase @@ -353,11 +264,6 @@ if [ ! -e server.properties ]; then esac fi - if [ -n "$GENERATOR_SETTINGS" ]; then - echo "Setting generator settings" - sed -i "/generator-settings\s*=/ c generator-settings=$GENERATOR_SETTINGS" /data/server.properties - fi - if [ -n "$DIFFICULTY" ]; then echo "Setting difficulty" case $DIFFICULTY in diff --git a/minecraft-server/start.sh b/minecraft-server/start.sh index 1612cc80..aad248a2 100755 --- a/minecraft-server/start.sh +++ b/minecraft-server/start.sh @@ -11,4 +11,9 @@ while lsof -- /start-minecraft; do echo -n "." sleep 1 done -exec /start-minecraft + +mkdir /home/minecraft +chown minecraft: /home/minecraft + +echo "Switching to user 'minecraft'" +exec sudo -E -u minecraft /start-minecraft