Compare commits

...

26 Commits
1.5.0 ... 1.8.0

Author SHA1 Message Date
Stephen Owen
4fe55b5a28 Added note on tweaking settings and using own map (#602) 2020-08-07 17:15:13 -05:00
Stephen Owen
bd503f224d Adds EULA to the 'quickstart' command in readme (#600)
* Adds EULA to the 'quickstart' command in readme

most people will start with the quickstart command, which won't work anymore now that EULA is required.  Modified the sample quickstart to include the new minimum params.

* Update README.md

Co-authored-by: Geoff Bourne <itzgeoff@gmail.com>

* Update README.md

Co-authored-by: Geoff Bourne <itzgeoff@gmail.com>

Co-authored-by: Geoff Bourne <itzgeoff@gmail.com>
2020-08-04 20:06:00 -05:00
Geoff Bourne
b5c91647ca Added testdata to dockerignore 2020-08-02 19:57:47 -05:00
Geoff Bourne
c359a0f2ac Changed MODPACK and MODS to only resolve effective URL when needed
For #592
2020-08-02 19:57:12 -05:00
Geoff Bourne
49d9f4a89d Separated autopause config file location to keep scripts read-only 2020-07-26 13:22:07 -05:00
Geoff Bourne
aebe35c9d4 misc: Refactor writeEula 2020-07-26 13:19:45 -05:00
Geoff Bourne
a26361c79f misc: Renamed start-deployCF to align with multiarch branch 2020-07-26 13:07:30 -05:00
Paul Zühlcke
a486458a08 Fixed "REPLACE_ENV_VARIABLES_EXCLUDE_PATHS" breaking cfg replacer when set. (#598) 2020-07-26 08:20:11 -05:00
nrgbistro
82b8401414 More filenames for modpack start scripts (#596) 2020-07-23 14:29:39 -05:00
Geoff Bourne
8b6ee91ec1 Added support for upgrading with USE_MODPACK_START_SCRIPT=false 2020-07-19 18:10:16 -05:00
Geoff Bourne
06cffd9e15 Ensured eula and other files brought over when not using CF start script (#591) 2020-07-19 16:29:41 -05:00
Geoff Bourne
beaccbcf3b Added option to set USE_MODPACK_START_SCRIPT=false for CF modpacks (#591) 2020-07-19 15:01:19 -05:00
Geoff Bourne
21ee5e2401 Changed handling of unrecognized VERSION and detect absent server in meta json
For #590
2020-07-19 12:22:15 -05:00
Paul Zühlcke
747c188824 Use -prune for "REPLACE_ENV_VARIABLES_EXCLUDE_PATHS" feature. (#588) 2020-07-18 18:31:29 -05:00
Geoff Bourne
692087dd25 Ensured ops.txt and white-list.txt are always provided for CURSEFORGE/FTB type (#584) 2020-07-18 13:49:40 -05:00
Geoff Bourne
6fe13e8654 Clarified "invalid type" message for FTBA on multiarch 2020-07-18 13:09:58 -05:00
Geoff Bourne
3b2b98b9fe Upgrade base image packages
For #586
2020-07-14 21:07:57 -05:00
Code Monad
796f2fe14a Add support for rcon password from file (#585) 2020-07-13 21:00:46 -05:00
Geoff Bourne
4fef391b64 misc: Switched maintainer label to opencontainers schema 2020-07-12 11:36:31 -05:00
Geoff Bourne
83f6cebd0b Merge pull request #581 from itzg/dev/add-ci-tests
Added CI tests
2020-07-11 14:29:59 -05:00
Geoff Bourne
90183ae823 ci: Don't restart failed container during test 2020-07-11 14:26:47 -05:00
Geoff Bourne
3c9df03584 ci: Only output server logs when failed 2020-07-11 14:13:51 -05:00
Geoff Bourne
367c6cfd92 ci: Added testing step to github actions 2020-07-11 14:09:08 -05:00
Geoff Bourne
5e75410e7c Confirm latest Paper jar is always downloaded 2020-07-11 13:30:39 -05:00
Geoff Bourne
38028f7d0c Confirm latest Spigot jar is always downloaded 2020-07-11 13:17:28 -05:00
Geoff Bourne
a07ae685e2 Fixed attempted rsync when WORLD not set 2020-07-11 13:09:48 -05:00
20 changed files with 305 additions and 120 deletions

View File

@@ -1,4 +1,5 @@
data data
testdata
examples examples
k8s-examples k8s-examples
.idea .idea

View File

@@ -16,7 +16,18 @@ on:
- "[0-9]+.[0-9]+.[0-9]+-adopt13" - "[0-9]+.[0-9]+.[0-9]+-adopt13"
jobs: jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run tests
run: |
tests/test.sh
build: build:
needs:
- test
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -32,4 +43,5 @@ jobs:
tag_with_sha: false tag_with_sha: false
cache_froms: itzg/minecraft-server:latest cache_froms: itzg/minecraft-server:latest
add_git_labels: true add_git_labels: true
labels: org.opencontainers.image.url=https://github.com/itzg/docker-minecraft-server,org.opencontainers.image.documentation=https://github.com/itzg/docker-minecraft-server
push: true push: true

View File

@@ -5,15 +5,12 @@ on:
branches: [ master ] branches: [ master ]
jobs: jobs:
build: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Build Docker image - name: Run tests
uses: docker/build-push-action@v1.1.0 run: |
with: tests/test.sh
tag_with_sha: true
cache_froms: itzg/minecraft-server:latest
push: false

View File

@@ -1,6 +1,9 @@
FROM openjdk:8u212-jre-alpine FROM openjdk:8u212-jre-alpine
LABEL maintainer "itzg" LABEL org.opencontainers.image.authors="Geoff Bourne <itzgeoff@gmail.com>"
# upgrade all packages since alpine jre8 base image tops out at 8u212
RUN apk -U --no-cache upgrade
RUN apk add --no-cache -U \ RUN apk add --no-cache -U \
openssl \ openssl \

View File

@@ -11,7 +11,7 @@ latest snapshot. See the _Versions_ section below for more information.
To simply use the latest stable version, run To simply use the latest stable version, run
docker run -d -p 25565:25565 --name mc itzg/minecraft-server docker run -d -p 25565:25565 --name mc -e EULA=TRUE itzg/minecraft-server
where the standard server port, 25565, will be exposed on your host machine. where the standard server port, 25565, will be exposed on your host machine.
@@ -35,6 +35,7 @@ With that you can easily view the logs, stop, or re-start the container:
docker stop mc docker stop mc
docker start mc docker start mc
*Be sure to always include `-e EULA=TRUE` in your commands, as Mojang/Microsoft requires EULA acceptance.*
## Looking for a Bedrock Dedicated Server ## Looking for a Bedrock Dedicated Server
@@ -269,10 +270,20 @@ the `/path/on/host` folder contents look like:
├── ops.json ├── ops.json
├── server.properties ├── server.properties
├── whitelist.json ├── whitelist.json
├── worlds
│   └── ... PLACE MAPS IN THEIR OWN FOLDERS HERE ...
└── ... └── ...
``` ```
If you add mods while the container is running, you'll need to restart it to pick those Providing a presistent `/data` mount is a good idea, both to persist the game world and to allow for the manual configuration which is sometimes needed.
For instance, imagine a scenario when the initial launch has completed, but you now want to change the worldmap for your server.
Assuming you have a shared directory to your container, you can then (after first launch) drag and drop your premade maps or worlds into the `\worlds\` directory. **Note:** each world should be placed in its own folder under the `\worlds\` directory.
Once your maps are in the proper path, you can then specify which map the server uses by changing the `level-name` value in `server.properties` to match the name of your map.
If you add mods or make changes to `server.properties` while the container is running, you'll need to restart it to pick those
up: up:
docker stop mc docker stop mc
@@ -291,6 +302,8 @@ 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 location, but still have multiple worlds with different server requirements
in either persistent volumes or a downloadable archive. in either persistent volumes or a downloadable archive.
### Replacing variables inside configs ### Replacing variables inside configs
Sometimes you have mods or plugins that require configuration information that is only available at runtime. Sometimes you have mods or plugins that require configuration information that is only available at runtime.
@@ -324,7 +337,13 @@ There are some limitations to what characters you can use.
Variables will be replaced in files with the following extensions: Variables will be replaced in files with the following extensions:
`.yml`, `.yaml`, `.txt`, `.cfg`, `.conf`, `.properties`. `.yml`, `.yaml`, `.txt`, `.cfg`, `.conf`, `.properties`.
Specific files can be excluded by listing their name (without path) in the variable `REPLACE_ENV_VARIABLES_EXCLUDES`. Paths can be excluded by listing them in the variable `REPLACE_ENV_VARIABLES_EXCLUDE_PATHS`. Specific files can be excluded by listing their name (without path) in the variable `REPLACE_ENV_VARIABLES_EXCLUDES`.
Paths can be excluded by listing them in the variable `REPLACE_ENV_VARIABLES_EXCLUDE_PATHS`. Path
excludes are recursive. Here is an example:
```
REPLACE_ENV_VARIABLES_EXCLUDE_PATHS="/data/plugins/Essentials/userdata /data/plugins/MyPlugin"
```
Here is a full example where we want to replace values inside a `database.yml`. Here is a full example where we want to replace values inside a `database.yml`.
@@ -507,6 +526,10 @@ The following example uses `/modpacks` as the container path as the pre-download
-e CF_SERVER_MOD=/modpacks/SkyFactory_4_Server_4.1.0.zip \ -e CF_SERVER_MOD=/modpacks/SkyFactory_4_Server_4.1.0.zip \
-p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server -p 25565:25565 -e EULA=TRUE --name mc itzg/minecraft-server
#### Buggy start scripts
Some modpacks have buggy or overly complex start scripts. You can avoid using the bundled start script and use this image's standard server-starting logic by adding `-e USE_MODPACK_START_SCRIPT=false`.
### Fixing "unable to launch forgemodloader" ### Fixing "unable to launch forgemodloader"
If your server's modpack fails to load with an error [like this](https://support.feed-the-beast.com/t/cant-start-crashlanding-server-unable-to-launch-forgemodloader/6028/2): If your server's modpack fails to load with an error [like this](https://support.feed-the-beast.com/t/cant-start-crashlanding-server-unable-to-launch-forgemodloader/6028/2):

View File

@@ -4,7 +4,7 @@
. /start-utils . /start-utils
sudo /usr/sbin/knockd -c /autopause/knockd-config.cfg -d sudo /usr/sbin/knockd -c /tmp/knockd-config.cfg -d
if [ $? -ne 0 ] ; then if [ $? -ne 0 ] ; then
while : while :
do do

5
start
View File

@@ -36,11 +36,6 @@ if [ $(id -u) = 0 ]; then
chown -R ${runAsUser}:${runAsGroup} /data chown -R ${runAsUser}:${runAsGroup} /data
fi fi
if [[ $(stat -c "%u" /autopause) != $UID ]]; then
log "Changing ownership of /autopause to $UID ..."
chown -R ${runAsUser}:${runAsGroup} /autopause
fi
if [[ ${SKIP_NSSWITCH_CONF^^} != TRUE ]]; then if [[ ${SKIP_NSSWITCH_CONF^^} != TRUE ]]; then
echo 'hosts: files dns' > /etc/nsswitch.conf echo 'hosts: files dns' > /etc/nsswitch.conf
fi fi

View File

@@ -4,18 +4,20 @@
log "Autopause functionality enabled" log "Autopause functionality enabled"
cp /autopause/knockd-config.cfg /tmp/knockd-config.cfg
# update server port to listen to # update server port to listen to
regseq="^\s*sequence\s*=\s*$SERVER_PORT\s*$" regseq="^\s*sequence\s*=\s*$SERVER_PORT\s*$"
linenum=$(grep -nm1 sequence /autopause/knockd-config.cfg | cut -d : -f 1 | tail -n1) linenum=$(grep -nm1 sequence /tmp/knockd-config.cfg | cut -d : -f 1 | tail -n1)
if ! [[ $(awk "NR==$linenum" /autopause/knockd-config.cfg) =~ $regseq ]]; then if ! [[ $(awk "NR==$linenum" /tmp/knockd-config.cfg) =~ $regseq ]]; then
sed -i "${linenum}s/sequence.*/sequence = $SERVER_PORT/" /autopause/knockd-config.cfg sed -i "${linenum}s/sequence.*/sequence = $SERVER_PORT/" /tmp/knockd-config.cfg
log "Updated server port in knockd config" log "Updated server port in knockd config"
fi fi
# update rcon port to listen to # update rcon port to listen to
regseq="^\s*sequence\s*=\s*$RCON_PORT\s*$" regseq="^\s*sequence\s*=\s*$RCON_PORT\s*$"
linenum=$(grep -nm2 sequence /autopause/knockd-config.cfg | cut -d : -f 1 | tail -n1) linenum=$(grep -nm2 sequence /tmp/knockd-config.cfg | cut -d : -f 1 | tail -n1)
if ! [[ $(awk "NR==$linenum" /autopause/knockd-config.cfg) =~ $regseq ]]; then if ! [[ $(awk "NR==$linenum" /tmp/knockd-config.cfg) =~ $regseq ]]; then
sed -i "${linenum}s/sequence.*/sequence = $RCON_PORT/" /autopause/knockd-config.cfg sed -i "${linenum}s/sequence.*/sequence = $RCON_PORT/" /tmp/knockd-config.cfg
log "Updated rcon port in knockd config" log "Updated rcon port in knockd config"
fi fi

View File

@@ -8,8 +8,7 @@ shopt -s nullglob
export HOME=/data export HOME=/data
if [ ! -e /data/eula.txt ]; then if [ ! -e /data/eula.txt ]; then
EULA="${EULA,,}" if ! isTrue "$EULA"; then
if [ "$EULA" != "true" ]; then
log "" log ""
log "Please accept the Minecraft EULA at" log "Please accept the Minecraft EULA at"
log " https://account.mojang.com/documents/minecraft_eula" log " https://account.mojang.com/documents/minecraft_eula"
@@ -19,12 +18,7 @@ if [ ! -e /data/eula.txt ]; then
exit 1 exit 1
fi fi
echo "# Generated via Docker on $(date)" > /data/eula.txt writeEula
if ! echo "eula=$EULA" >> /data/eula.txt; then
log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}"
exit 2
fi
fi fi
@@ -45,6 +39,22 @@ if [[ $PROXY ]]; then
sleep 5 sleep 5
fi fi
if [[ $RCON_PASSWORD_FILE ]]; then
log ""
if [ ! -e ${RCON_PASSWORD_FILE} ]; then
log "Initial RCON password file ${RCON_PASSWORD_FILE} does not seems to exist."
log "Please ensure your configuration."
log "If you are using Docker Secrets feature, please check this for further information: "
log " https://docs.docker.com/engine/swarm/secrets"
log ""
exit 1
else
RCON_PASSWORD=$(cat ${RCON_PASSWORD_FILE})
export RCON_PASSWORD
fi
log ""
fi
export SERVER_PROPERTIES=/data/server.properties export SERVER_PROPERTIES=/data/server.properties
export VERSIONS_JSON=https://launchermeta.mojang.com/mc/game/version_manifest.json export VERSIONS_JSON=https://launchermeta.mojang.com/mc/game/version_manifest.json
@@ -55,11 +65,8 @@ case "X$VERSION" in
XSNAPSHOT|Xsnapshot) XSNAPSHOT|Xsnapshot)
VANILLA_VERSION=$(curl -fsSL $VERSIONS_JSON | jq -r '.latest.snapshot') VANILLA_VERSION=$(curl -fsSL $VERSIONS_JSON | jq -r '.latest.snapshot')
;; ;;
X[1-9]*)
VANILLA_VERSION=$VERSION
;;
*) *)
VANILLA_VERSION=$(curl -fsSL $VERSIONS_JSON | jq -r '.latest.release') VANILLA_VERSION=$VERSION
;; ;;
esac esac
export VANILLA_VERSION export VANILLA_VERSION
@@ -96,7 +103,7 @@ case "${TYPE^^}" in
;; ;;
FTB|CURSEFORGE) FTB|CURSEFORGE)
exec ${SCRIPTS:-/}start-deployFTB "$@" exec ${SCRIPTS:-/}start-deployCF "$@"
;; ;;
VANILLA) VANILLA)
@@ -129,8 +136,9 @@ case "${TYPE^^}" in
*) *)
log "Invalid type: '$TYPE'" log "Invalid type: '$TYPE'"
log "Must be: VANILLA, FORGE, BUKKIT, SPIGOT, PAPER, FTBA, CURSEFORGE, SPONGEVANILLA," log "Must be: VANILLA, FORGE, BUKKIT, SPIGOT, PAPER, FTBA (multiarch-only),"
log " CUSTOM, CURSE_INSTANCE, MAGMA, MOHIST, CATSERVER" log " CURSE_INSTANCE, CURSEFORGE, SPONGEVANILLA,"
log " CUSTOM, MAGMA, MOHIST, CATSERVER"
exit 1 exit 1
;; ;;

View File

@@ -62,8 +62,12 @@ function downloadSpigot {
downloadUrl="https://cdn.getbukkit.org/${getbukkitFlavor}/${getbukkitFlavor}-${VANILLA_VERSION}.jar" downloadUrl="https://cdn.getbukkit.org/${getbukkitFlavor}/${getbukkitFlavor}-${VANILLA_VERSION}.jar"
fi fi
if [ -f $SERVER ]; then
# tell curl to only download when newer
zarg="-z $SERVER"
fi
log "Downloading $match from $downloadUrl ..." log "Downloading $match from $downloadUrl ..."
curl -fsSL -o $SERVER "$downloadUrl" curl -fsSL -o $SERVER $zarg "$downloadUrl"
if [[ $? != 0 || $(grep -c "DOCTYPE html" $SERVER) != 0 ]]; then if [[ $? != 0 || $(grep -c "DOCTYPE html" $SERVER) != 0 ]]; then
cat <<EOF cat <<EOF
@@ -89,12 +93,12 @@ case "$TYPE" in
;; ;;
esac esac
if [ ! -f $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then if isTrue "$BUILD_SPIGOT_FROM_SOURCE" || isTrue "$BUILD_FROM_SOURCE"; then
if isTrue "$BUILD_SPIGOT_FROM_SOURCE" || isTrue "$BUILD_FROM_SOURCE"; then if [ ! -f $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then
buildSpigotFromSource buildSpigotFromSource
else fi
downloadSpigot else
fi downloadSpigot
fi fi
# Normalize on Spigot for operations below # Normalize on Spigot for operations below

View File

@@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
set -e
. ${SCRIPTS:-/}start-utils . ${SCRIPTS:-/}start-utils
export FTB_BASE_DIR=/data/FeedTheBeast export FTB_BASE_DIR=/data/FeedTheBeast
@@ -9,18 +11,67 @@ export TYPE=FEED-THE-BEAST
FTB_SERVER_MOD=${FTB_SERVER_MOD:-$CF_SERVER_MOD} FTB_SERVER_MOD=${FTB_SERVER_MOD:-$CF_SERVER_MOD}
log "Looking for Feed-The-Beast / CurseForge server modpack." log "Looking for Feed-The-Beast / CurseForge server modpack."
if [[ -z $FTB_SERVER_MOD ]]; then requireVar FTB_SERVER_MOD
log "Environment variable FTB_SERVER_MOD not set."
log "Set FTB_SERVER_MOD to the file name of the FTB server modpack." if ! isTrue ${USE_MODPACK_START_SCRIPT:-true}; then
log "(And place the modpack in the /data directory.)" if ! [ -f ${FTB_SERVER_MOD} ]; then
log "ERROR unable to find requested modpack file ${FTB_SERVER_MOD}"
exit 2 exit 2
fi
needsInstall=true
installMarker=/data/.curseforge-installed
if [ -f $installMarker ]; then
if [ "$(cat $installMarker)" != "${FTB_SERVER_MOD}" ]; then
log "Upgrading modpack"
serverJar=$(find ${FTB_BASE_DIR} -not -name "forge*installer.jar" -name "forge*.jar")
if [[ "${serverJar}" ]]; then
rm -rf $(dirname "${serverJar}")/{mods,*.jar,libraries,resources,scripts}
fi
else
needsInstall=false
fi
fi
if $needsInstall; then
log "Unpacking FTB server modpack ${FTB_SERVER_MOD} ..."
mkdir -p ${FTB_BASE_DIR}
unzip -o ${FTB_SERVER_MOD} -d ${FTB_BASE_DIR} | awk '{printf "."} END {print ""}'
forgeInstallerJar=$(find ${FTB_BASE_DIR} -name "forge*installer.jar")
if [[ -z "${forgeInstallerJar}" ]]; then
log "ERROR Unable to find forge installer in modpack."
log " Make sure you downloaded the server files."
exit 2
fi
log "Installing forge server"
(cd $(dirname "${forgeInstallerJar}"); java -jar $(basename ${forgeInstallerJar}) --installServer) | awk '{printf "."} END {print ""}'
echo "${FTB_SERVER_MOD}" > $installMarker
fi
export SERVER=$(find ${FTB_BASE_DIR} -not -name "forge*installer.jar" -name "forge*.jar")
if [[ -z "${SERVER}" || ! -f "${SERVER}" ]]; then
log "ERROR unable to locate installed forge server jar"
isDebugging && find ${FTB_BASE_DIR} -name "forge*.jar"
exit 2
fi
export FTB_DIR=$(dirname "${SERVER}")
exec ${SCRIPTS:-/}start-finalSetupWorld $@
fi fi
entryScriptExpr=" entryScriptExpr="
-name ServerStart.sh -name ServerStart.sh
-o -name serverstart.sh
-o -name ServerStartLinux.sh -o -name ServerStartLinux.sh
-o -name LaunchServer.sh -o -name LaunchServer.sh
-o -name server-start.sh -o -name server-start.sh
-o -name startserver.sh
-o -name StartServer.sh
" "
if [[ -d ${FTB_BASE_DIR} ]]; then if [[ -d ${FTB_BASE_DIR} ]]; then

View File

@@ -5,17 +5,18 @@
: ${PAPERBUILD:=latest} : ${PAPERBUILD:=latest}
export SERVER=paper_server-${VANILLA_VERSION}-${PAPERBUILD}.jar export SERVER=paper_server-${VANILLA_VERSION}-${PAPERBUILD}.jar
if [ ! -f "$SERVER" ] || [ -n "$FORCE_REDOWNLOAD" ]; then if [ -f "$SERVER" ] && ! isTrue "$FORCE_REDOWNLOAD"; then
downloadUrl=${PAPER_DOWNLOAD_URL:-https://papermc.io/api/v1/paper/${VANILLA_VERSION}/${PAPERBUILD}/download} zarg="-z '$SERVER'"
log "Downloading Paper $VANILLA_VERSION (build $PAPERBUILD) from $downloadUrl ..."
curl -fsSL -o "$SERVER" "$downloadUrl"
if [ ! -f "$SERVER" ]; then
log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3
fi
fi fi
# Normalize on Spigot for operations below downloadUrl=${PAPER_DOWNLOAD_URL:-https://papermc.io/api/v1/paper/${VANILLA_VERSION}/${PAPERBUILD}/download}
log "Downloading Paper $VANILLA_VERSION (build $PAPERBUILD) from $downloadUrl ..."
if ! curl -fsSL -o "$SERVER" $zarg "$downloadUrl"; then
log "ERROR: failed to download from $downloadUrl (status=$?)"
exit 3
fi
# Normalize on Spigot for downstream operations
export TYPE=SPIGOT export TYPE=SPIGOT
export SKIP_LOG4J_CONFIG=true export SKIP_LOG4J_CONFIG=true

View File

@@ -26,6 +26,9 @@ if [ ! -e $SERVER ] || [ -n "$FORCE_REDOWNLOAD" ]; then
if [ $result != 0 ]; then if [ $result != 0 ]; then
log "ERROR failed to obtain version manifest from $versionManifestUrl ($result)" log "ERROR failed to obtain version manifest from $versionManifestUrl ($result)"
exit 1 exit 1
elif [ $serverDownloadUrl = null ]; then
log "ERROR version $VANILLA_VERSION does not provide a server download"
exit 1
fi fi
debug "Downloading server from $serverDownloadUrl" debug "Downloading server from $serverDownloadUrl"

View File

@@ -7,14 +7,20 @@
if isTrue "${REPLACE_ENV_VARIABLES}"; then if isTrue "${REPLACE_ENV_VARIABLES}"; then
log "Replacing env variables in configs that match the prefix $ENV_VARIABLE_PREFIX..." log "Replacing env variables in configs that match the prefix $ENV_VARIABLE_PREFIX..."
findExcludes= # File excludes
fileExcludes=
for f in ${REPLACE_ENV_VARIABLES_EXCLUDES}; do for f in ${REPLACE_ENV_VARIABLES_EXCLUDES}; do
findExcludes="${findExcludes} -not -name $f" fileExcludes="${fileExcludes} -not -name $f"
done done
for p in ${REPLACE_ENV_VARIABLES_EXCLUDE_PATHS}; do
findExcludes="${findExcludes} -not -path \"*$p*\"" # Directory excludes (recursive)
done dirExcludes=$(join_by " -o -path " ${REPLACE_ENV_VARIABLES_EXCLUDE_PATHS})
isDebugging && echo "Using find exclusion: $findExcludes" if [[ $dirExcludes ]]; then
dirExcludes=" -type d ( -path ${dirExcludes} ) -prune -o"
fi
isDebugging && echo "Using find file exclusions: $fileExcludes"
isDebugging && echo "Using find directory exclusions: $dirExcludes"
while IFS='=' read -r name value ; do while IFS='=' read -r name value ; do
# check if name of env variable matches the prefix # check if name of env variable matches the prefix
@@ -29,10 +35,12 @@ if isTrue "${REPLACE_ENV_VARIABLES}"; then
fi fi
log "Replacing $name with $value ..." log "Replacing $name with $value ..."
find /data/ -type f \ find /data/ \
$dirExcludes \
-type f \
\( -name "*.yml" -or -name "*.yaml" -or -name "*.txt" -or -name "*.cfg" \ \( -name "*.yml" -or -name "*.yaml" -or -name "*.txt" -or -name "*.cfg" \
-or -name "*.conf" -or -name "*.properties" \) \ -or -name "*.conf" -or -name "*.properties" \) \
$findExcludes \ $fileExcludes \
-exec sed -i 's#${'"$name"'}#'"$value"'#g' {} \; -exec sed -i 's#${'"$name"'}#'"$value"'#g' {} \;
fi fi
done < <(env) done < <(env)

View File

@@ -18,42 +18,60 @@ fi
# If supplied with a URL for a modpack (simple zip of jars), download it and unpack # If supplied with a URL for a modpack (simple zip of jars), download it and unpack
if [[ "$MODPACK" ]]; then if [[ "$MODPACK" ]]; then
EFFECTIVE_MODPACK_URL=$(curl -Ls -o /dev/null -w %{url_effective} $MODPACK) if isURL "${MODPACK}"; then
case "X$EFFECTIVE_MODPACK_URL" in if [[ "${MODPACK}" == *.zip ]]; then
X[Hh][Tt][Tt][Pp]*.zip) downloadUrl="${MODPACK}"
else
downloadUrl=$(curl -Ls -o /dev/null -w %{url_effective} $MODPACK)
if ! [[ $downloadUrl == *.zip ]]; then
log "ERROR Invalid URL given for MODPACK: $downloadUrl resolved from $MODPACK"
log " Must be HTTP or HTTPS and a ZIP file"
exit 1
fi
fi
log "Downloading mod/plugin pack via HTTP" log "Downloading mod/plugin pack via HTTP"
log " from $EFFECTIVE_MODPACK_URL ..." log " from $downloadUrl ..."
if ! curl -sSL -o /tmp/modpack.zip "$EFFECTIVE_MODPACK_URL"; then if ! curl -sSL -o /tmp/modpack.zip "$downloadUrl"; then
log "ERROR: failed to download from $EFFECTIVE_MODPACK_URL" log "ERROR: failed to download from $downloadUrl"
exit 2 exit 2
fi fi
if [ "$TYPE" = "SPIGOT" ]; then if [ "$TYPE" = "SPIGOT" ]; then
mkdir -p /data/plugins mkdir -p /data/plugins
if ! unzip -o -d /data/plugins /tmp/modpack.zip; then if ! unzip -o -d /data/plugins /tmp/modpack.zip; then
log "ERROR: failed to unzip the modpack from $EFFECTIVE_MODPACK_URL" log "ERROR: failed to unzip the modpack from $downloadUrl"
fi fi
else else
mkdir -p /data/mods mkdir -p /data/mods
if ! unzip -o -d /data/mods /tmp/modpack.zip; then if ! unzip -o -d /data/mods /tmp/modpack.zip; then
log "ERROR: failed to unzip the modpack from $EFFECTIVE_MODPACK_URL" log "ERROR: failed to unzip the modpack from $downloadUrl"
fi fi
fi fi
rm -f /tmp/modpack.zip rm -f /tmp/modpack.zip
;;
*) else
log "Invalid URL given for modpack: Must be HTTP or HTTPS and a ZIP file" log "ERROR Invalid URL given for MODPACK: $MODPACK"
;; exit 1
esac fi
fi fi
# If supplied with a URL for a plugin download it. # If supplied with a URL for a plugin download it.
if [[ "$MODS" ]]; then if [[ "$MODS" ]]; then
for i in ${MODS//,/ } for i in ${MODS//,/ }
do do
EFFECTIVE_MOD_URL=$(curl -Ls -o /dev/null -w %{url_effective} $i) if isURL $i; then
case "X$EFFECTIVE_MOD_URL" in if [[ $i == *.jar ]]; then
X[Hh][Tt][Tt][Pp]*.jar) EFFECTIVE_MOD_URL=$i
else
EFFECTIVE_MOD_URL=$(curl -Ls -o /dev/null -w %{url_effective} $i)
if ! [[ $EFFECTIVE_MOD_URL == *.jar ]]; then
log "ERROR Invalid URL given in MODS: $EFFECTIVE_MOD_URL resolved from $i"
log " Must be HTTP or HTTPS and a JAR file"
exit 1
fi
fi
log "Downloading mod/plugin via HTTP" log "Downloading mod/plugin via HTTP"
log " from $EFFECTIVE_MOD_URL ..." log " from $EFFECTIVE_MOD_URL ..."
if ! curl -sSL -o /tmp/${EFFECTIVE_MOD_URL##*/} $EFFECTIVE_MOD_URL; then if ! curl -sSL -o /tmp/${EFFECTIVE_MOD_URL##*/} $EFFECTIVE_MOD_URL; then
@@ -69,12 +87,12 @@ do
mv /tmp/${EFFECTIVE_MOD_URL##*/} /data/mods/${EFFECTIVE_MOD_URL##*/} mv /tmp/${EFFECTIVE_MOD_URL##*/} /data/mods/${EFFECTIVE_MOD_URL##*/}
fi fi
rm -f /tmp/${EFFECTIVE_MOD_URL##*/} rm -f /tmp/${EFFECTIVE_MOD_URL##*/}
;;
*) else
log "Invalid URL given for modpack: Must be HTTP or HTTPS and a JAR file" log "ERROR Invalid URL given in MODS: $i"
;; exit 1
esac fi
done done
fi fi
if [[ "$MANIFEST" ]]; then if [[ "$MANIFEST" ]]; then

View File

@@ -10,7 +10,7 @@ else
worldDest=/data/$LEVEL worldDest=/data/$LEVEL
fi fi
if [[ "$WORLD" ]] && isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ]; then if [[ "$WORLD" ]] && ( isTrue "${FORCE_WORLD_COPY}" || [ ! -d "$worldDest" ] ); then
if isURL $WORLD; then if isURL $WORLD; then
curl -fsSL "$WORLD" -o /tmp/world.zip curl -fsSL "$WORLD" -o /tmp/world.zip
zipSrc=/tmp/world.zip zipSrc=/tmp/world.zip

View File

@@ -158,49 +158,60 @@ if isTrue "${DEBUG_MEMORY}"; then
free -m free -m
fi fi
JVM_OPTS="-Xms${INIT_MEMORY} -Xmx${MAX_MEMORY} ${JVM_OPTS}"
function copyFilesForCurseForge() {
# copy player modification files unconditionally since their
# processing into json is additive anyway
[ -f /data/ops.txt ] && cp -f /data/ops.txt ${FTB_DIR}/
[ -f /data/white-list.txt ] && cp -f /data/white-list.txt ${FTB_DIR}/
if [ ! -e "${FTB_DIR}/server-icon.png" -a -e /data/server-icon.png ]; then
cp -f /data/server-icon.png ${FTB_DIR}/
fi
cp -f /data/eula.txt "${FTB_DIR}/"
}
mcServerRunnerArgs="--stop-duration 60s" mcServerRunnerArgs="--stop-duration 60s"
if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then if [[ ${TYPE} == "CURSE_INSTANCE" ]]; then
JVM_OPTS="-Xms${INIT_MEMORY} -Xmx${MAX_MEMORY} ${JVM_OPTS}"
if isTrue ${DEBUG_EXEC}; then if isTrue ${DEBUG_EXEC}; then
set -x set -x
fi fi
exec mc-server-runner ${mcServerRunnerArgs} \ exec mc-server-runner ${mcServerRunnerArgs} \
--cf-instance-file "${CURSE_INSTANCE_JSON}" \ --cf-instance-file "${CURSE_INSTANCE_JSON}" \
java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar _SERVERJAR_ "$@" $EXTRA_ARGS java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar _SERVERJAR_ "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "FEED-THE-BEAST" && "${SERVER}" ]]; then
copyFilesForCurseForge
cd "${FTB_DIR}"
log "Starting CurseForge server in ${FTB_DIR}..."
if isTrue ${DEBUG_EXEC}; then
set -x
fi
exec mc-server-runner ${bootstrapArgs} ${mcServerRunnerArgs} java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar $(basename "${SERVER}") "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "FEED-THE-BEAST" ]]; then elif [[ ${TYPE} == "FEED-THE-BEAST" ]]; then
mcServerRunnerArgs="${mcServerRunnerArgs} --shell bash" mcServerRunnerArgs="${mcServerRunnerArgs} --shell bash"
if [ ! -e "${FTB_DIR}/ops.json" -a -e /data/ops.txt ]; then copyFilesForCurseForge
cp -f /data/ops.txt ${FTB_DIR}/
fi
if [ ! -e "${FTB_DIR}/whitelist.json" -a -e /data/white-list.txt ]; then cat > "${FTB_DIR}/settings-local.sh" <<EOF
cp -f /data/white-list.txt ${FTB_DIR}/
fi
if [ ! -e "${FTB_DIR}/server-icon.png" -a -e /data/server-icon.png ]; then
cp -f /data/server-icon.png ${FTB_DIR}/
fi
cp -f /data/eula.txt "${FTB_DIR}/"
cat > "${FTB_DIR}/settings-local.sh" <<EOF
export MIN_RAM="${INIT_MEMORY}" export MIN_RAM="${INIT_MEMORY}"
export MAX_RAM="${MAX_MEMORY}" export MAX_RAM="${MAX_MEMORY}"
export JAVA_PARAMETERS="${JVM_XX_OPTS} -Xms${INIT_MEMORY} ${JVM_OPTS} $expandedDOpts" export JAVA_PARAMETERS="${JVM_XX_OPTS} -Xms${INIT_MEMORY} ${JVM_OPTS} $expandedDOpts"
EOF EOF
# patch CurseForge cfg file, if present # patch CurseForge cfg file, if present
if [ -f "${FTB_DIR}/settings.cfg" ]; then if [ -f "${FTB_DIR}/settings.cfg" ]; then
sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${MAX_MEMORY}/" "${FTB_DIR}/settings.cfg" sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${MAX_MEMORY}/" "${FTB_DIR}/settings.cfg"
fi fi
cd "${FTB_DIR}" cd "${FTB_DIR}"
log "Running FTB ${FTB_SERVER_START} in ${FTB_DIR} ..." log "Running FTB ${FTB_SERVER_START} in ${FTB_DIR} ..."
if isTrue ${DEBUG_EXEC}; then if isTrue ${DEBUG_EXEC}; then
set -x set -x
fi fi
exec mc-server-runner ${mcServerRunnerArgs} "${FTB_SERVER_START}" exec mc-server-runner ${mcServerRunnerArgs} "${FTB_SERVER_START}"
else else
# If we have a bootstrap.txt file... feed that in to the server stdin # If we have a bootstrap.txt file... feed that in to the server stdin
if [ -f /data/bootstrap.txt ]; then if [ -f /data/bootstrap.txt ]; then
@@ -208,7 +219,6 @@ else
fi fi
log "Starting the Minecraft server..." log "Starting the Minecraft server..."
JVM_OPTS="-Xms${INIT_MEMORY} -Xmx${MAX_MEMORY} ${JVM_OPTS}"
if isTrue ${DEBUG_EXEC}; then if isTrue ${DEBUG_EXEC}; then
set -x set -x
fi fi

View File

@@ -1,5 +1,7 @@
#!/bin/bash #!/bin/bash
function join_by { local d=$1; shift; echo -n "$1"; shift; printf "%s" "${@/#/$d}"; }
function isURL { function isURL {
local value=$1 local value=$1
@@ -106,4 +108,17 @@ requireVar() {
log "ERROR: $1 is required to be set" log "ERROR: $1 is required to be set"
exit 1 exit 1
fi fi
if [ -z "${!1}" ]; then
log "ERROR: $1 is required to be set"
exit 1
fi
}
function writeEula() {
if ! echo "# Generated via Docker on $(date)
eula=${EULA,,}
" > /data/eula.txt; then
log "ERROR: unable to write eula to /data. Please make sure attached directory is writable by uid=${UID}"
exit 2
fi
} }

View File

@@ -0,0 +1,17 @@
version: "3.8"
services:
sut:
depends_on:
- mc
image: itzg/mc-monitor:0.6.0
command: status --host mc --retry-interval 1s --retry-limit 120
mc:
restart: "no"
build:
context: ..
cache_from:
- itzg/minecraft-server:latest
environment:
EULA: "TRUE"

17
tests/test.sh Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/bash
cd $(dirname $0)
failed=false
args="-f docker-compose.test.yml"
docker-compose $args run sut || failed=true
echo "
Result: failed=$failed"
$failed && docker-compose $args logs mc
docker-compose $args down -v
if $failed; then
exit 1
fi