diff --git a/.github/workflows/auto-deploy-staging.yml b/.github/workflows/auto-deploy-staging.yml deleted file mode 100644 index 4d395f2..0000000 --- a/.github/workflows/auto-deploy-staging.yml +++ /dev/null @@ -1,20 +0,0 @@ -name: "Auto Deploy Staging Branches" - -on: - push: - branches: - - "staging*" - -jobs: - build: - if: ${{ startsWith(github.ref, 'refs/heads/staging') }} - uses: MitchTalmadge/AMP-dockerized/.github/workflows/build.yml@staging - with: - for_deploy: true - - deploy: - needs: [build] - uses: MitchTalmadge/AMP-dockerized/.github/workflows/deploy-staging.yml@staging - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c5dfe1c..e433494 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -7,18 +7,12 @@ on: required: true type: boolean workflow_dispatch: - push: - paths: - - Dockerfile - - .dockerignore - - entrypoint/** - - .github/workflows/build.yml pull_request: paths: - Dockerfile - .dockerignore - entrypoint/** - - .github/workflows/build.yml + - .github/workflows/**.yml jobs: build: @@ -26,28 +20,26 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - arch: [amd64] + arch: [amd64,arm64] steps: - name: "Checkout Git Repo" - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: fetch-depth: 0 - name: "Set up QEMU" - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: "Set up Docker Buildx" - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: "Build Docker Image" - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: - build-args: | - "CACHE_AMP_UPGRADE=${{ inputs.for_deploy == true }}" context: . platforms: linux/${{ matrix.arch }} tags: amp-dockerized:latest outputs: type=docker,dest=/tmp/docker-image-${{ matrix.arch }}.tar - name: "Upload Docker Image Artifact" if: ${{ inputs.for_deploy == true }} - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: image-${{ matrix.arch }} path: /tmp/docker-image-${{ matrix.arch }}.tar diff --git a/.github/workflows/check-for-updates.yml b/.github/workflows/check-for-updates.yml deleted file mode 100644 index f7c36fe..0000000 --- a/.github/workflows/check-for-updates.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: "Check for Updates" - -on: - schedule: - - cron: "*/15 * * * *" # Every 15 mins - workflow_dispatch: - create: - tags: - - "v[0-9]+" - -jobs: - # Find out what version of AMP exists online right now. - get_latest_version: - name: "Get Latest Version" - runs-on: ubuntu-latest - outputs: - amp_core_version: ${{ steps.parse.outputs.amp_core_version }} - amp_instmgr_version: ${{ steps.parse.outputs.amp_instmgr_version }} - steps: - - name: "Download AMP Versions" - run: wget https://cubecoders.com/AMPVersions.json -O /tmp/AMPVersions.json - - name: "Parse Versions" - id: parse - run: | - echo "::set-output name=amp_core_version::$(jq -r '.AMPCore' /tmp/AMPVersions.json | sed -e 's/\.//g')" - echo "::set-output name=amp_instmgr_version::$(jq -r '.InstanceManagerCLI' /tmp/AMPVersions.json | sed -e 's/\.//g')" - - # Find out when the latest version of AMP was modified. - # Sometimes patches are released under the same version, so only this value will change. - get_last_modified: - name: "Get Last Modified" - runs-on: ubuntu-latest - outputs: - amp_last_modified: ${{ steps.parse.outputs.amp_last_modified }} - steps: - - name: "Get Last Modified" - id: parse - # Converts the last-modified header to seconds since epoch. - run: echo "::set-output name=amp_last_modified::$(curl https://cubecoders.com/Downloads/AMP_Latest.zip --head --silent | awk 'match($0, /last-modified:\s+(.+)\s+/, a) {print a[1]}' | date -f - +%s)" - - # Determine if we have a tag for this combination of version and last-modified. - check_for_tag: - name: "Check for Tag" - runs-on: ubuntu-latest - needs: [ get_latest_version, get_last_modified ] - outputs: - tag_exists: ${{ steps.check_for_tag.outputs.tag_exists }} - git_release_version: ${{ steps.get_git_version.outputs.git_latest_release_version }} - amp_core_version: ${{ needs.get_latest_version.outputs.amp_core_version }} - amp_instmgr_version: ${{ needs.get_latest_version.outputs.amp_instmgr_version }} - amp_last_modified: ${{ needs.get_last_modified.outputs.amp_last_modified }} - - steps: - - name: "Checkout" - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: "Determine Latest Release Version" - id: get_git_version - run: echo "::set-output name=git_latest_release_version::$(git tag -l --sort=-creatordate | grep -E '^v?[0-9]+$' -m 1)" - - name: "Compose Expected Tag" - id: compose_tag - run: echo "::set-output name=expected_tag::${{steps.get_git_version.outputs.git_latest_release_version}}-ampcore${{needs.get_latest_version.outputs.amp_core_version}}-ampinstmgr${{needs.get_latest_version.outputs.amp_instmgr_version}}-${{needs.get_last_modified.outputs.amp_last_modified}}" - - name: "Check for Expected Tag" - id: check_for_tag - run: echo "::set-output name=tag_exists::$(git tag | grep -q ${{steps.compose_tag.outputs.expected_tag}} && echo '1' || echo '0')" - - build: - name: "Build" - needs: [ check_for_tag ] - if: ${{ needs.check_for_tag.outputs.tag_exists == '0' && github.ref == 'refs/heads/master' }} - uses: MitchTalmadge/AMP-Dockerized/.github/workflows/build.yml@master - with: - for_deploy: true - - deploy: - name: "Deploy" - needs: [ build, check_for_tag ] - uses: MitchTalmadge/AMP-dockerized/.github/workflows/deploy-prod.yml@master - with: - git_release_version: ${{ needs.check_for_tag.outputs.git_release_version }} - amp_core_version: ${{ needs.check_for_tag.outputs.amp_core_version }} - amp_instmgr_version: ${{ needs.check_for_tag.outputs.amp_instmgr_version }} - amp_last_modified: ${{ needs.check_for_tag.outputs.amp_last_modified }} - secrets: - DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} - DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 5c3395a..78fa8f3 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -1,58 +1,43 @@ name: "Deploy Production" on: - workflow_call: - inputs: - git_release_version: - required: true - type: string - amp_core_version: - required: true - type: string - amp_instmgr_version: - required: true - type: string - amp_last_modified: - required: true - type: string - secrets: - DOCKERHUB_USERNAME: - required: true - DOCKERHUB_TOKEN: - required: true + push: + branches: + - "master" + tags: + - v* jobs: + build: + uses: ./.github/workflows/build.yml + with: + for_deploy: true + deploy: name: "Deploy" runs-on: ubuntu-latest + needs: build steps: - name: "Download Docker Image Artifacts" uses: actions/download-artifact@v2 with: path: /tmp - - name: "Load Docker Image" + - name: "Get Tag Name" + id: get_tag_name + run: echo "TAG_NAME=$(echo ${GITHUB_REF#refs/tags/})" >> $GITHUB_ENV + - name: "Load Docker Images" + id: load_images run: | - for f in $(find /tmp -type f -iname 'docker-image*.tar' -print); do + TAGS="" + for f in $(find /tmp -type f -iname 'docker-image-*.tar' -print); do + ARCH=$(echo ${f} | sed -E 's/.*docker-image-(.*).tar/\1/') docker load --input ${f} + TAG="mitchtalmadge/amp-dockerized:${{ steps.get_tag_name.outputs.TAG_NAME }}-${ARCH}" + TAGS="${TAGS} ${TAG}" + docker tag amp-dockerized:latest ${TAG} done + echo "TAGS=${TAGS}" >> $GITHUB_OUTPUT docker image ls -a - - name: "Tag Docker Images" - run: | - docker tag amp-dockerized:latest mitchtalmadge/amp-dockerized:latest - docker tag amp-dockerized:latest mitchtalmadge/amp-dockerized:${{inputs.git_release_version}} - docker tag amp-dockerized:latest mitchtalmadge/amp-dockerized:${{inputs.git_release_version}}-ampcore${{inputs.amp_core_version}}-ampinstmgr${{inputs.amp_instmgr_version}} - docker tag amp-dockerized:latest mitchtalmadge/amp-dockerized:${{inputs.git_release_version}}-ampcore${{inputs.amp_core_version}}-ampinstmgr${{inputs.amp_instmgr_version}}-${{inputs.amp_last_modified}} - - name: "Checkout Git Repo" - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: "Commit Git Tag" - run: | - git config user.name github-actions - git config user.email github-actions@github.com - TAG=${{inputs.git_release_version}}-ampcore${{inputs.amp_core_version}}-ampinstmgr${{inputs.amp_instmgr_version}}-${{inputs.amp_last_modified}} - git tag -a "${TAG}" -m "Auto Release Latest AMP Version" || { echo "Tag already exists"; exit; } - git push --follow-tags - name: "Login to Docker Hub" uses: docker/login-action@v1 with: @@ -60,3 +45,10 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: "Deploy to Docker Hub" run: docker image push --all-tags mitchtalmadge/amp-dockerized + - name: "Deploy Multi-Arch Manifests" + run: | + MANIFESTS="mitchtalmadge/amp-dockerized:latest mitchtalmadge/amp-dockerized:${{ steps.get_tag_name.outputs.TAG_NAME }}" + for m in ${MANIFESTS}; do + docker manifest create ${m} ${{ steps.load_images.outputs.TAGS }} + docker manifest push ${m} + done diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 6c0a551..b2daaa4 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -1,33 +1,45 @@ name: "Deploy Staging" on: - workflow_call: - secrets: - DOCKERHUB_USERNAME: - required: true - DOCKERHUB_TOKEN: - required: true + push: + branches: + - "staging*" + paths: + - Dockerfile + - .dockerignore + - entrypoint/** + - .github/workflows/**.yml jobs: + build: + if: ${{ startsWith(github.ref, 'refs/heads/staging') }} + uses: ./.github/workflows/build.yml + with: + for_deploy: true + deploy: name: "Deploy Staging" runs-on: ubuntu-latest + needs: build steps: - name: "Download Docker Image Artifacts" uses: actions/download-artifact@v2 with: path: /tmp - name: "Load Docker Images" + id: load_images run: | - for f in $(find /tmp -type f -iname 'docker-image*.tar' -print); do + TAGS="" + BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/}) + for f in $(find /tmp -type f -iname 'docker-image-*.tar' -print); do + ARCH=$(echo ${f} | sed -E 's/.*docker-image-(.*).tar/\1/') docker load --input ${f} + TAG="mitchtalmadge/amp-dockerized:${BRANCH_NAME}-${ARCH}" + TAGS="${TAGS} ${TAG}" + docker tag amp-dockerized:latest ${TAG} done + echo "TAGS=${TAGS}" >> $GITHUB_OUTPUT docker image ls -a - - name: "Extract Branch Name" - id: extract_branch - run: echo "::set-output name=name::$(echo ${GITHUB_REF#refs/heads/})" - - name: "Tag Docker Image" - run: docker tag amp-dockerized:latest mitchtalmadge/amp-dockerized:${{ steps.extract_branch.outputs.name }} - name: "Login to Docker Hub" uses: docker/login-action@v1 with: @@ -35,3 +47,9 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} - name: "Deploy to Docker Hub" run: docker image push --all-tags mitchtalmadge/amp-dockerized + - name: "Deploy Multi-Arch Manifest" + run: | + BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/}) + MANIFEST="mitchtalmadge/amp-dockerized:${BRANCH_NAME}" + docker manifest create ${MANIFEST} ${{ steps.load_images.outputs.TAGS }} + docker manifest push ${MANIFEST} diff --git a/Dockerfile b/Dockerfile index 52f128e..ed76f57 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,6 @@ -FROM ubuntu:20.04 - -# Set to false to skip downloading the AMP cache which is used for faster upgrades. -ARG CACHE_AMP_UPGRADE=true +FROM debian:12-slim + +ARG TARGETPLATFORM # Set by Docker, see https://docs.docker.com/engine/reference/builder/#automatic-platform-args-in-the-global-scope ENV UID=1000 ENV GID=1000 @@ -9,20 +8,24 @@ ENV TZ=Etc/UTC ENV PORT=8080 ENV USERNAME=admin ENV PASSWORD=password -ENV LICENCE=notset -ENV MODULE=ADS ENV IPBINDING=0.0.0.0 +ENV AMP_AUTO_UPDATE=true +ENV AMP_LICENCE=notset +ENV AMP_MODULE=ADS +ENV AMP_RELEASE_STREAM=Mainline ENV AMP_SUPPORT_LEVEL=UNSUPPORTED ENV AMP_SUPPORT_TOKEN=AST0/MTAD ENV AMP_SUPPORT_TAGS="nosupport docker community unofficial unraid" ENV AMP_SUPPORT_URL="https://github.com/MitchTalmadge/AMP-dockerized/" +ENV LD_LIBRARY_PATH="./:/opt/cubecoders/amp/:/AMP/" ARG DEBIAN_FRONTEND=noninteractive # Initialize RUN apt-get update && \ apt-get install -y --no-install-recommends \ + apt-transport-https \ jq \ sed \ tzdata \ @@ -34,7 +37,6 @@ RUN apt-get update && \ /var/lib/apt/lists/* \ /var/tmp/* - # Configure Locales RUN apt-get update && \ apt-get install -y --no-install-recommends locales && \ @@ -52,59 +54,55 @@ ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 -# Add Mono apt source +# Install Mono RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - apt-transport-https \ + apt-get install -y \ dirmngr \ - software-properties-common \ - gnupg \ - ca-certificates && \ - apt-get -y clean && \ - apt-get -y autoremove --purge && \ - rm -rf \ - /tmp/* \ - /var/lib/apt/lists/* \ - /var/tmp/* -RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \ - echo "deb https://download.mono-project.com/repo/ubuntu stable-focal main" | tee /etc/apt/sources.list.d/mono-official-stable.list - - -# Install Mono Certificates -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - ca-certificates-mono && \ + ca-certificates \ + gnupg && \ + gpg --homedir /tmp --no-default-keyring --keyring /usr/share/keyrings/mono-official-archive-keyring.gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF && \ + echo "deb [signed-by=/usr/share/keyrings/mono-official-archive-keyring.gpg] https://download.mono-project.com/repo/debian stable-buster main" | tee /etc/apt/sources.list.d/mono-official-stable.list && \ + apt-get update && \ + apt-get install -y mono-devel && \ apt-get -y clean && \ apt-get -y autoremove --purge && \ rm -rf \ /tmp/* \ /var/lib/apt/lists/* \ /var/tmp/* -RUN wget -O /tmp/cacert.pem https://curl.haxx.se/ca/cacert.pem && \ - cert-sync /tmp/cacert.pem +# Declare and install AMP dependencies -# Install AMP dependencies -RUN ls -al /usr/local/bin/ -RUN dpkg --add-architecture i386 && \ - apt-get update && \ - apt-get install -y \ - # -------------------- - # Dependencies for AMP: - tmux \ +# AMP core dependencies +ARG AMPDEPS="\ + bzip2 \ + coreutils \ + curl \ + gdb \ git \ - socat \ - unzip \ + git-lfs \ + gnupg \ iputils-ping \ + libc++-dev \ + libc6 \ + libatomic1 \ + libgdiplus \ + liblua5.3-0 \ + libpulse-dev \ + libsqlite3-0 \ + libzstd1 \ + locales \ + numactl \ procps \ - # -------------------- - # Dependencies for Minecraft: - openjdk-17-jre-headless \ - openjdk-11-jre-headless \ - openjdk-8-jre-headless \ - # -------------------- - # Dependencies for srcds (TF2, GMod, ...) - lib32gcc1 \ + software-properties-common \ + socat \ + tmux \ + unzip \ + xz-utils" + +# srcds (TF2, GMod, ...) dependencies +ARG SRCDSDEPS="\ + lib32gcc-s1 \ lib32stdc++6 \ lib32z1 \ libbz2-1.0:i386 \ @@ -113,12 +111,37 @@ RUN dpkg --add-architecture i386 && \ libncurses5:i386 \ libsdl2-2.0-0 \ libsdl2-2.0-0:i386 \ - libtinfo5:i386 \ - # -------------------- - # Dependencies for Factorio: - xz-utils \ - # -------------------- - && \ + libtinfo5:i386" + +# Needed for games that require Wine and Xvfb +ARG WINEXVFB="\ + fonts-wine \ + libwine \ + libwine:i386 \ + python3 \ + python3-venv \ + cabextract \ + wine \ + wine32 \ + wine64 \ + wine-binfmt \ + winbind \ + xauth \ + xvfb" + +RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ + dpkg --add-architecture aarch64 && \ + apt-get update && \ + apt-get install -y \ + $AMPDEPS; \ + else \ + dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y \ + $AMPDEPS \ + $SRCDSDEPS \ + $WINEXVFB; \ + fi && \ apt-get -y clean && \ apt-get -y autoremove --purge && \ rm -rf \ @@ -126,8 +149,13 @@ RUN dpkg --add-architecture i386 && \ /var/lib/apt/lists/* \ /var/tmp/* -# Set Java default -RUN update-alternatives --set java /usr/lib/jvm/java-17-openjdk-amd64/bin/java +# Install Adoptium JDK +RUN wget -O - https://packages.adoptium.net/artifactory/api/gpg/key/public | tee /etc/apt/keyrings/adoptium.asc && \ + echo "deb [signed-by=/etc/apt/keyrings/adoptium.asc] https://packages.adoptium.net/artifactory/deb $(awk -F= '/^VERSION_CODENAME/{print$2}' /etc/os-release) main" | tee /etc/apt/sources.list.d/adoptium.list && \ + apt-get update && \ + apt-get install -y temurin-8-jdk temurin-11-jdk temurin-17-jdk temurin-21-jdk && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* # Manually install ampinstmgr by extracting it from the deb package. # Docker doesn't have systemctl and other things that AMP's deb postinst expects, @@ -136,10 +164,15 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends \ software-properties-common \ dirmngr \ - apt-transport-https && \ - # Add CubeCoders repository and key - apt-key adv --fetch-keys http://repo.cubecoders.com/archive.key && \ - apt-add-repository "deb http://repo.cubecoders.com/ debian/" && \ + apt-transport-https + +# Add CubeCoders repository and key +RUN wget -qO - http://repo.cubecoders.com/archive.key | gpg --dearmor > /etc/apt/trusted.gpg.d/cubecoders-archive-keyring.gpg && \ + if [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ + apt-add-repository "deb http://repo.cubecoders.com/aarch64 debian/"; \ + else \ + apt-add-repository "deb http://repo.cubecoders.com/ debian/"; \ + fi && \ apt-get update && \ # Just download (don't actually install) ampinstmgr apt-get install -y --no-install-recommends --download-only ampinstmgr && \ @@ -154,15 +187,6 @@ RUN apt-get update && \ /var/lib/apt/lists/* \ /var/tmp/* -# Get the latest AMP Core to pre-cache upgrades. -RUN if [ "$CACHE_AMP_UPGRADE" = "true" ]; then \ - echo "Pre-caching AMP Upgrade..." && \ - wget https://cubecoders.com/AMPVersions.json -O /tmp/AMPVersions.json && \ - wget https://cubecoders.com/Downloads/AMP_Latest.zip -O /opt/AMPCache-$(cat /tmp/AMPVersions.json | jq -r '.AMPCore' | sed -e 's/\.//g').zip; \ - else echo "Skipping AMP Upgrade Pre-cache."; \ - fi - - # Set up environment COPY entrypoint /opt/entrypoint RUN chmod -R +x /opt/entrypoint diff --git a/README.md b/README.md index 5568541..7c76e0d 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,10 @@ Updates to AMP are automatically bundled into new Docker images. We check for up You can make an issue if you need help, but I am not always available for quick assistance. Using AMP in this unofficial docker container is an advanced endeavour and you may need to do a little self-debugging and experimentation. Please remember to make backups of important data. +If you need help with AMP when using this image, please [create an issue](https://github.com/MitchTalmadge/AMP-dockerized/issues/new) in this repository. + +If you have coding skills and find this repository useful, please consider helping out by answering questions in the issues or making pull requests to fix bugs. I really can't do this alone. + **Please DO NOT bug CubeCoders for support. They do not support nor endorse this image and will tell you that you are on your own.** ## Unraid @@ -101,9 +105,9 @@ Just a quick note about ports: some games use TCP, some games use UDP. Make sure ### Licence -| Name | Description | Default Value | -|-----------|----------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| -| `LICENCE` | The licence key for CubeCoders AMP. You can retrieve or buy this on [their website.](https://manage.cubecoders.com/) | No Default. AMP will not boot without a real licence. | +| Name | Description | Default Value | +|---------------|--------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| +| `AMP_LICENCE` | The licence key for CubeCoders AMP. You can retrieve or buy this on [their website.](https://manage.cubecoders.com/) | No Default. AMP will not boot without a real licence. | **Important Details:** - _Americans:_ This is spelled licenCe not licenSe. Got me a few times. @@ -112,9 +116,9 @@ Just a quick note about ports: some games use TCP, some games use UDP. Make sure ### Module -| Name | Description | Default Value | -|----------|------------------------------------------------------------------|---------------| -| `MODULE` | Which Module to use for the main instance created by this image. | `ADS` | +| Name | Description | Default Value | +|--------------|-----------------------------------------------------------------------------------------------------------------------------------------------------|---------------| +| `AMP_MODULE` | Which Module to use for the Main instance created by this image (note: changing this value will have no effect after the Main instance is created). | `ADS` | To run multiple game servers under this image, use the default value of `ADS` (Application Deployment Service) which allows you to create various modules from the web ui. @@ -165,10 +169,10 @@ Example: `TZ=America/Denver` | `USERNAME` | The username of the admin user created on first boot. | `admin` | | `PASSWORD` | The password of the admin user. This value is only used when creating the new user. If you use the default value, please change it after first sign-in. | `password` | -### Nightly Builds -| Name | Description | Default Value | -|-------|----------------------------------------------------------------------|---------------| -| `NIGHTLY` | Set to any value to enable nightly builds. All instances will be migrated to nightly builds on next image start. Unset this variable to go back to MainLine builds (stable releases). | UNSET | +### Release Stream +| Name | Description | Default Value | +|----------------------|----------------------------------------------------------------------------------------------------|---------------| +| `AMP_RELEASE_STREAM` | Valid values are `Mainline` or `Development`. Don't change this unless you know what you're doing. | `Mainline` | ## Volumes @@ -201,8 +205,11 @@ To restart the AMP instances, just restart the Docker container. Or, just put [CloudFlare](https://www.cloudflare.com/) and its free SSL cert in front of your web UI and save yourself hours of pain. # Upgrading AMP +To upgrade, just restart your container! On startup, we check for updates and install them if they are available. -To upgrade, all you have to do is pull our latest Docker image! We automatically check for AMP updates every hour. When a new version is released, we build and publish an image both as a standalone tag and on `:latest`. +| Name | Description | Default Value | +|-------------------|-------------------------------------------------------------------------------------------------|---------------| +| `AMP_AUTO_UPDATE` | Set to `false` if you would not like AMP to automatically update when you reboot the container. | `true` | # Contributing diff --git a/entrypoint/main.sh b/entrypoint/main.sh index e21eced..caa2e6a 100644 --- a/entrypoint/main.sh +++ b/entrypoint/main.sh @@ -1,5 +1,6 @@ #!/bin/bash -e -set +o xtrace +#set -o xtrace +set -e echo "----------------------" echo "Starting AMP-Dockerized..." @@ -8,114 +9,46 @@ echo "Note: This is an UNOFFICIAL IMAGE for CubeCoders AMP. This was created by echo "Please, DO NOT contact CubeCoders (Discord or otherwise) for technical support when using this image." echo "They do not support nor endorse this image and will not help you." echo "Instead, please direct support requests to https://github.com/MitchTalmadge/AMP-dockerized/issues." -echo "We are happy to help you there!" echo "Thank you!!" echo "----------------------" echo "" -# Run user startup script -STARTUP_SCRIPT="/home/amp/scripts/startup.sh" -if [ -f ${STARTUP_SCRIPT} ]; then - echo "Running startup script..." - chmod +x ${STARTUP_SCRIPT} - /bin/bash ${STARTUP_SCRIPT} -fi - -# Copy the pre-cached AMP Core from the image into the location AMP expects. -# This will allow upgrades to use the cache and not need to do any downloads. -echo "Copying AMP Core..." -mkdir -p /home/amp/.ampdata/instances/ -cp /opt/AMPCache* /home/amp/.ampdata/instances/ +source /opt/entrypoint/utils.sh +source /opt/entrypoint/routines.sh +trap 'handle_error' ERR +trap_with_arg 'shutdown' INT TERM HUP QUIT KILL -# Create user and group that will own the config files (if they don't exist already). -echo "Ensuring AMP user exists..." -if [ ! "$(getent group ${GID})" ]; then - # Create group - addgroup \ - --gid ${GID} \ - amp -fi -APP_GROUP=$(getent group ${GID} | awk -F ":" '{ print $1 }') -if [ ! "$(getent passwd ${UID})" ]; then - # Create user - adduser \ - --uid ${UID} \ - --shell /bin/bash \ - --no-create-home \ - --ingroup ${APP_GROUP} \ - --system \ - amp +# Migrate legacy vars +export AMP_LICENCE=${LICENCE:-${AMP_LICENCE:-"notset"}} +export AMP_MODULE=${MODULE:-${AMP_MODULE:-"ADS"}} +if [ ! -z "${NIGHTLY}" ]; then + export AMP_RELEASE_STREAM="Development" fi -APP_USER=$(getent passwd ${UID} | awk -F ":" '{ print $1 }') -# Let all volume data be owned by the new user. -echo "Ensuring correct file permissions..." -chown -R ${APP_USER}:${APP_GROUP} /home/amp +run_startup_script -# Set Timezone -echo "Setting timezone from TZ env var..." -ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ >/etc/timezone -dpkg-reconfigure --frontend noninteractive tzdata +create_amp_user -# Ensure a Licence was set -if [ ${LICENCE} = "notset" ]; then - echo "Error: no Licence specified. You need to have a valid AMP licence from cubecoders.com specified in the LICENCE environment variable" - exit 1 -fi - -# Create Main Instance if not exists -echo "Making sure Main instance exists..." -if [ ! $(su ${APP_USER} --command "ampinstmgr ShowInstancesList" | grep "Instance Name" | awk '{ print $4 }' | grep "Main") ]; then - echo "Creating Main instance... (This can take a while)" - su ${APP_USER} --command "ampinstmgr CreateInstance \"${MODULE}\" Main \"${IPBINDING}\" \"${PORT}\" \"${LICENCE}\" \"${USERNAME}\" \"${PASSWORD}\"" | grep --line-buffered -v -E '\[[-#]+\]' -fi +check_licence -# Set instances to MainLine or Nightly -if [ ! -z "$NIGHTLY" ]; then - # Nightly - echo "Setting all instances to use Nightly updates..." - su ${APP_USER} --command "ampinstmgr ShowInstancesList" | grep "Instance Name" | awk '{ print $4 }' | while read -r INSTANCE_NAME; do - echo "> ${INSTANCE_NAME}:" - su ${APP_USER} --command "ampinstmgr Switch \"${INSTANCE_NAME}\" Nightly" | grep --line-buffered -v -E '\[[-#]+\]' - done -else - # MainLine - echo "Setting all instances to use MainLine updates..." - su ${APP_USER} --command "ampinstmgr ShowInstancesList" | grep "Instance Name" | awk '{ print $4 }' | while read -r INSTANCE_NAME; do - echo "> ${INSTANCE_NAME}:" - su ${APP_USER} --command "ampinstmgr Switch \"${INSTANCE_NAME}\" MainLine True" | grep --line-buffered -v -E '\[[-#]+\]' - done -fi +configure_timezone -# Upgrade instances -echo "Upgrading Instances..." -su ${APP_USER} --command "ampinstmgr UpgradeAll" | grep --line-buffered -v -E '\[[-#]+\]' +check_file_permissions -# Set Main instance to start on boot if not already. -echo "Ensuring Main Instance will Start on Boot..." -su ${APP_USER} --command "ampinstmgr ShowInstanceInfo Main | grep \"Start on Boot\" | grep \"No\" && ampinstmgr SetStartBoot Main yes || true" +configure_main_instance -# Startup -echo "Starting AMP..." -su ${APP_USER} --command "ampinstmgr StartBoot" -echo "AMP Started." +configure_release_stream -# Trap SIGTERM for a graceful shutdown -shutdown() { - echo "Shutting Down AMP..." - su ${APP_USER} --command "ampinstmgr StopAll" - echo "Shutdown Complete." - exit 0 -} -trap "shutdown" SIGTERM +if [ ${AMP_AUTO_UPDATE} = "true" ]; then + upgrade_instances +else + echo "Skipping automatic updates." +fi -# Java Notice -echo "----------------------" -echo "NOTICE: Java 17 is now the default in this image. Java 16 has been removed in preference of Java 17, which is LTS." -echo "Use the Java Configuration section in the AMP Web UI to select a specific version. Otherwise, Java 17 will be used automatically." -echo "----------------------" +start_amp # Sleep -echo "Entrypoint Sleeping. Logs can be viewed through AMP web UI or at ampdata/instances/Main/AMP_Logs" +echo "AMP is now running. Logs can be viewed through AMP web UI or at ampdata/instances/Main/AMP_Logs" +monitor_amp & tail -f /dev/null & wait $! diff --git a/entrypoint/routines.sh b/entrypoint/routines.sh new file mode 100644 index 0000000..2bb93c8 --- /dev/null +++ b/entrypoint/routines.sh @@ -0,0 +1,145 @@ +#!/bin/bash + +check_file_permissions() { + echo "Checking file permissions..." + chown -R ${APP_USER}:${APP_GROUP} /home/amp +} + +check_licence() { + echo "Checking licence..." + if [ ${AMP_LICENCE} = "notset" ]; then + handle_error "AMP_LICENCE is not set. You need to have a valid AMP licence from cubecoders.com specified in the AMP_LICENCE environment variable" + fi + # TODO: Find a way to test the licence validity +} + +configure_main_instance() { + echo "Checking Main instance existence..." + if ! does_main_instance_exist; then + echo "Creating Main instance... (This can take a while)" + run_amp_command "CreateInstance \"${AMP_MODULE}\" Main \"${IPBINDING}\" \"${PORT}\" \"${AMP_LICENCE}\" \"${USERNAME}\" \"${PASSWORD}\"" | consume_progress_bars + if ! does_main_instance_exist; then + handle_error "Failed to create Main instance. Please check your configuration." + fi + fi + + echo "Setting Main instance to start on boot..." + run_amp_command "ShowInstanceInfo Main" | grep "Start on Boot" | grep -q "No" && run_amp_command "SetStartBoot Main yes" || true +} + +configure_release_stream() { + echo "Setting release stream to ${AMP_RELEASE_STREAM}..." + # Example Output from ShowInstancesList: + # [Info] AMP Instance Manager v2.4.5.4 built 26/06/2023 18:20 + # [Info] Stream: Mainline / Release - built by CUBECODERS/buildbot on CCL-DEV + # Instance ID │ 295e9fc7-9987-4e4e-94a6-183cb04de459 + # Module │ ADS + # Instance Name │ Main + # Friendly Name │ Main + # URL │ http://127.0.0.1:8080/ + # Running │ No + # Runs in Container │ No + # Runs as Shared │ No + # Start on Boot │ Yes + # AMP Version │ 2.4.5.4 + # Release Stream │ Mainline + # Data Path │ /home/amp/.ampdata/instances/Main + run_amp_command "ShowInstancesList" | grep "Instance Name" | awk '{ print $4 }' | while read -r INSTANCE_NAME; do + local RELEASE_STREAM=$(run_amp_command "ShowInstanceInfo \"${INSTANCE_NAME}\"" | grep "Release Stream" | awk '{ print $4 }') + if [ "${RELEASE_STREAM}" != "${AMP_RELEASE_STREAM}" ]; then + echo "Changing release stream of ${INSTANCE_NAME} from ${RELEASE_STREAM} to ${AMP_RELEASE_STREAM}..." + run_amp_command "ChangeInstanceStream \"${INSTANCE_NAME}\" ${AMP_RELEASE_STREAM} True" | consume_progress_bars + # Since we changed release streams we have to force an upgrade + run_amp_command "UpgradeInstance \"${INSTANCE_NAME}\"" | consume_progress_bars + fi + done +} + +configure_timezone() { + echo "Configuring timezone..." + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ >/etc/timezone + dpkg-reconfigure --frontend noninteractive tzdata +} + +create_amp_user() { + echo "Creating AMP group..." + if [ ! "$(getent group ${GID})" ]; then + # Create group + addgroup \ + --gid ${GID} \ + amp + fi + APP_GROUP=$(getent group ${GID} | awk -F ":" '{ print $1 }') + echo "Group Created: ${APP_GROUP} (${GID})" + + echo "Creating AMP user..." + if [ ! "$(getent passwd ${UID})" ]; then + # Create user + adduser \ + --uid ${UID} \ + --shell /bin/bash \ + --no-create-home \ + --disabled-password \ + --gecos "" \ + --ingroup ${APP_GROUP} \ + amp + fi + APP_USER=$(getent passwd ${UID} | awk -F ":" '{ print $1 }') + echo "User Created: ${APP_USER} (${UID})" +} + +handle_error() { + # Prints a nice error message and exits. + # Usage: handle_error "Error message" + local error_message="$1" + echo "Sorry! An error occurred during startup and AMP needs to shut down." + if [ ! -z "${error_message}" ]; then + echo "Error message: ${error_message}" + fi + echo "Please direct any questions or concerns to https://github.com/MitchTalmadge/AMP-dockerized/issues" + exit 1 +} + +monitor_amp() { + # Periodically process pending tasks (e.g. upgrade, reboots, ...) + while true; do + run_amp_command_silently "ProcessPendingTasks" + sleep 5 # The UI's restart timeout is 10 seconds, so let's be safe. + done +} + +run_startup_script() { + # Users may provide their own startup script for installing dependencies, etc. + STARTUP_SCRIPT="/home/amp/scripts/startup.sh" + if [ -f ${STARTUP_SCRIPT} ]; then + echo "Running startup script..." + chmod +x ${STARTUP_SCRIPT} + /bin/bash ${STARTUP_SCRIPT} + fi +} + +shutdown() { + echo "Shutting down... (Signal ${1})" + if [ -n "${AMP_STARTED}" ] && [ "${AMP_STARTED}" -eq 1 ] && [ "${1}" != "KILL" ]; then + stop_amp + fi + exit 0 +} + +start_amp() { + echo "Starting AMP..." + run_amp_command "StartBoot" + export AMP_STARTED=1 + echo "AMP Started!" +} + +stop_amp() { + echo "Stopping AMP..." + run_amp_command "StopAll" + echo "AMP Stopped." +} + +upgrade_instances() { + echo "Upgrading instances..." + run_amp_command "UpgradeAll" | consume_progress_bars +} \ No newline at end of file diff --git a/entrypoint/utils.sh b/entrypoint/utils.sh new file mode 100644 index 0000000..34bfcd2 --- /dev/null +++ b/entrypoint/utils.sh @@ -0,0 +1,25 @@ +#!/bin/bash +consume_progress_bars() { + # See https://github.com/MitchTalmadge/AMP-dockerized/issues/25#issuecomment-670251321 + grep --line-buffered -v -E '\[[-#]+\]' +} + +does_main_instance_exist() { + run_amp_command "ShowInstancesList" | grep "Instance Name" | awk '{ print $4 }' | grep -q "Main" +} + +run_amp_command() { + su ${APP_USER} --command "ampinstmgr $1" +} + +run_amp_command_silently() { + su ${APP_USER} --command "ampinstmgr --silent $1" +} + +trap_with_arg() { + # Credit https://stackoverflow.com/a/2183063/2364405 + func="$1" ; shift + for sig ; do + trap "$func $sig" "$sig" + done +} diff --git a/example-configs/README.md b/example-configs/README.md new file mode 100644 index 0000000..72aa479 --- /dev/null +++ b/example-configs/README.md @@ -0,0 +1,8 @@ +# Example Configs + +## Which one do I use? +- If you're using Unraid's Docker tool, this directory doesn't apply to you. +- If you think there's a chance that you'll ever want to run more than one game server, start with the `ads` config. This will launch an "ADS" instance which can be used to create other instances. +- If you want to run one specific game only, you can just use one of those configs (e.g. `factorio`) +- If you have an old McMyAdmin license (if you don't know what this is, you don't have one), then you must use the `mcmyadmin` config. +- These are just examples -- you can of course make your own config! You don't even have to use `docker compose` if you don't want to, and know what you're doing. \ No newline at end of file