palworld-server-docker icon indicating copy to clipboard operation
palworld-server-docker copied to clipboard

Feat: Add pre and post update, start, backup, and shutdown discord hooks.

Open v4de opened this issue 1 year ago • 15 comments
trafficstars

Context

  • I would like to be able to add custom sh commands and discord webhooks before and after server is started or shutdown. Backup hooks were added as a bonus because I felt it may be useful in the future.

Choices

  • Used lloesche/valheim-server-docker previously and used this feature while hosting the container in the past. Would like to have the same functionality or better

Test instructions

Tested discord webhooks

  1. docker build . -t v4de/palworld-server-docker:0.1
  2. Generate a webhook to be for with discord
  3. Added following environment variables to docker-compose.yml
  - DISCORD_WEBHOOK=<place-webhook-here>
  - DISCORD_PRE_INIT_MESSAGE="Server initializing..."
  - DISCORD_POST_INIT_MESSAGE="Server started"
  - DISCORD_PRE_BACKUP_MESSAGE="Trying to backup..."
  - DISCORD_POST_BACKUP_MESSAGE="Backup created at $$FILE_PATH"
  - DISCORD_PRE_SHUTDOWN_MESSAGE="Server shutting down..."
  - DISCORD_POST_SHUTDOWN_MESSAGE="Server stopped"
  - 'PRE_INIT_HOOK=curl -sfSL -H "Content-Type: application/json" -d "{\"username\":\"Palworld\",\"content\":\"$$(eval echo $$DISCORD_PRE_INIT_MESSAGE)\"}" $$DISCORD_WEBHOOK'
  - 'POST_INIT_HOOK=curl -sfSL -H "Content-Type: application/json" -d "{\"username\":\"Palworld\",\"content\":\"$$(eval echo $$DISCORD_POST_INIT_MESSAGE)\"}" $$DISCORD_WEBHOOK'
  - 'PRE_BACKUP_HOOK=curl -sfSL -H "Content-Type: application/json" -d "{\"username\":\"Palworld\",\"content\":\"$$(eval echo $$DISCORD_PRE_BACKUP_MESSAGE)\"}" $$DISCORD_WEBHOOK'
  - 'POST_BACKUP_HOOK=curl -sfSL -H "Content-Type: application/json" -d "{\"username\":\"Palworld\",\"content\":\"$$(eval echo $$DISCORD_POST_BACKUP_MESSAGE)\"}" $$DISCORD_WEBHOOK'
  - 'PRE_SHUTDOWN_HOOK=curl -sfSL -H "Content-Type: application/json" -d "{\"username\":\"Palworld\",\"content\":\"$$(eval echo $$DISCORD_PRE_SHUTDOWN_MESSAGE)\"}" $$DISCORD_WEBHOOK'
  - 'POST_SHUTDOWN_HOOK=curl -sfSL -H "Content-Type: application/json" -d "{\"username\":\"Palworld\",\"content\":\"$$(eval echo $$DISCORD_POST_SHUTDOWN_MESSAGE)\"}" $$DISCORD_WEBHOOK'
  1. docker compose up -d --no-deps --build
  2. docker exec palworld-server backup
  3. docker compose down
  4. Validate expected messages received by discord image

Tested backup after shutdown

  1. Added following environment variable
  - POST_SHUTDOWN_HOOK=backup
  1. docker compose up -d
  2. note current backups and timestamps
  3. docker compose down
  4. found additional backup has been created with latest timestamp.

Checklist before requesting a review

  • [x] I have performed a self-review of my code
  • [x] I've added documentation about this change to the README.
  • [x] I've not introduced breaking changes.

v4de avatar Jan 28 '24 06:01 v4de

Well these are optional and would allow others to extend the container as they want. I understand that this should be only for advanced users, maybe I can make a note of that in the readme.

Unfortunately palworld is currently not running as a service so its difficult for me to grab an accurate status. This could be another enhancement.

When I place the hook at the end of start.sh I am unable to send a message && sleep 60 seconds, as the term_handler will have already run the rcon shutdown before anyone is notified.

2024-01-28T19:35:29.369379798Z *****SIGTERM BEGIN*****
2024-01-28T19:35:29.395356988Z Complete Save
2024-01-28T19:35:29.425128085Z The server will shut down in 1 seconds. Please prepare to exit the game.
2024-01-28T19:35:33.034047136Z dlmopen steamservice.so failed: steamservice.so: cannot open shared object file: No such file or directory
2024-01-28T19:35:33.852180758Z Shutdown handler: cleanup.
2024-01-28T19:35:33.875764572Z *****HI START.SH END*****
2024-01-28T19:35:34.427063991Z *****SIGTERM END*****
2024-01-28T19:35:34.427682703Z *****HI INIT.SH END*****

If the concern is security I could make this only for the discord hooks for now, as this is the most valuable for me right now:

DISCORD_WEBHOOK="https://discord.com/api/webhooks/$DISCORD_WEBHOOK_ID"

  if [ -n "$DISCORD_WEBHOOK" ]; then
      echo "DISCORD_PRE_INIT_JSON: $DISCORD_PRE_INIT_JSON"
      curl -sfSL -H "Content-Type: application/json" -d "$DISCORD_PRE_INIT_JSON" "$DISCORD_WEBHOOK"'
  fi

I can also move the hooks to another sh and have it run by steam user only:

# run as steam user
su steam -c ./hook.sh discord_hook $DISCORD_JSON $DISCORD_WEBHOOK &

Open to more suggestions as well.

v4de avatar Jan 28 '24 19:01 v4de

tbh, I really like the dedicated discord hooks idea, keeps it more simple and I can imagine that a lot of people would like such a feature

thijsvanloef avatar Jan 28 '24 20:01 thijsvanloef

I think a Discord notifier is a great idea and I'm eager to use it myself.

Term is meant to catch stopping the container so it must shutdown quickly. It's about preserving the save data. For shutdown I would create a separate shutdown script and have that run the notifier. Although to get notified you'd have to run docker exec palworld-server nice_shutdown but that way you could set the timeout instead of 1 second.

Recommend timeout for curl: curl --connect-timeout $DISCORD_TIMEOUT ...

If you're only doing discord then you need at least these environmental vars

  • DISCORD_WEBHOOK
  • DISCORD_USER
  • DISCORD_TIMEOUT
  • NICE_SHUTDOWN_TIME

The messages as environmental variables are a nice touch although I'm not sure how necessary they are.

Dashboy1998 avatar Jan 29 '24 01:01 Dashboy1998

@v4de is this PR still active?

thijsvanloef avatar Jan 31 '24 09:01 thijsvanloef

hey @thijsvanloef, ill work on this today. I have been busy with other work.

v4de avatar Jan 31 '24 16:01 v4de

@v4de no problem at all! Was just curious, take your time :)

thijsvanloef avatar Jan 31 '24 16:01 thijsvanloef

The messages as environmental variables are a nice touch although I'm not sure how necessary they are.

@Dashboy1998 We could make some standard json formatting which will reduce the amount of variables. Currently I have been using a dansgaming lamball icon and some basic colors and messages:

image

Not sure how to give the ability to choose to have some messages and not others. Will just add to all the places I believe helpful for notifications right now.

v4de avatar Jan 31 '24 17:01 v4de

The messages as environmental variables are a nice touch although I'm not sure how necessary they are.

@Dashboy1998 We could make some standard json formatting which will reduce the amount of variables. Currently I have been using a dansgaming lamball icon and some basic colors and messages:

image

Not sure how to give the ability to choose to have some messages and not others. Will just add to all the places I believe helpful for notifications right now.

I think the message variables are a good idea although I would specify default values for the messages, timeout, and even user.

Still not sure how to get a good shutdown warning other than a custom shutdown script otherwise I worry about people changing the NICE_SHUTDOWN_TIME but not the stop_grace_period.

Dashboy1998 avatar Jan 31 '24 19:01 Dashboy1998

@thijsvanloef, @Dashboy1998, I think its ready for another review when you have some time.

Decided to scrap a lot of the custom message variables in favor of having variables in the messages like backup file_path and auto_update_warn_minutes. I could not find a way to expand those variables from within another variable without using eval.

Also moved the post shutdown hook to start.sh. I could not find a way to trigger a message for shutting down without putting it in the term_handler. However I used the steam user to call it to hopefully reduce security concerns, and sent it to the background with "&" to allow the term_handler to continue. I have used that in a few places where messages indicate something is "in-progress". I would prefer users not to have to learn another way to shut down the container.

v4de avatar Feb 05 '24 09:02 v4de

Hi @v4de, Thanks for the work! will look at it tonight!

thijsvanloef avatar Feb 05 '24 10:02 thijsvanloef

@thijsvanloef Changed the syntax for the discord.sh to make it less messy. I wanted to expose the script some how, but agree no good way to do that right now. Also agree with moving it out of usr/bin. Sorry for all the linting changes, will try to keep that very minimal in the future.

v4de avatar Feb 05 '24 20:02 v4de

Replying to @Dashboy1998 :

Assuming your game is update to date then the order update completed message may be displayed before the server is started message. If there is an update then the order is correct. It's just a timing issue in the script.

I have seen this also in my testing, I am not sure why it was happening so quick, I removed the success from running in the background anymore.

I am getting no messages for running backup. I am getting no messages for running update.

This is interesting, I was seeing backup messages in my testing. Let me test this again, maybe I changed something after I tested.

Please fix all the spell check errors for shell SC2086.

I think @thijsvanloef assisted with the linting, I also updated some when changing the command.

v4de avatar Feb 05 '24 20:02 v4de

If there is an update then the order is correct. It's just a timing issue in the script.

I have seen this also in my testing, I am not sure why it was happening so quick, I removed the success from running in the background anymore.

I suspect the issue is one curl command beating the other. Not sure how to prevent that other than not running it in the background like you changed it or going to the complicated process of making a FIFO for the discord messages.

I am getting no messages for running backup. I am getting no messages for running update.

This is interesting, I was seeing backup messages in my testing. Let me test this again, maybe I changed something after I tested.

Strange. Here's my docker compose

services:
   palworld:
      image: thijsvanloef/palworld-server-docker:test
      build:
         dockerfile: Dockerfile
      restart: unless-stopped
      container_name: palworld-server-test
      stop_grace_period: 30s # Set to however long you are willing to wait for the container to gracefully stop
      ports:
        - 8212:8211/udp
        - 27015:27015/udp # Required if you want your server to show up in the community servers tab
      environment:
         - PUID=1000
         - PGID=1000
         - PORT=8211 # Optional but recommended
         - PLAYERS=16 # Optional but recommended
         - SERVER_PASSWORD=worldofpals # Optional but recommended
         - MULTITHREADING=true
         - RCON_ENABLED=true
         - RCON_PORT=25575
         - TZ=UTC
         - ADMIN_PASSWORD=adminPasswordHere
         - COMMUNITY=false  # Enable this if you want your server to show up in the community servers tab, USE WITH SERVER_PASSWORD!
         - SERVER_NAME=World of Pals
         - SERVER_DESCRIPTION=palworld-server-docker by Thijs van Loef
         - DISCORD_WEBHOOK_ID=1234/abde
      volumes:
         - ./palworld:/palworld/ 

Dashboy1998 avatar Feb 05 '24 20:02 Dashboy1998

Ok its working for me now, all the conditions were still checking for ID. Pull latest and use DISCORD_WEBHOOK_URL now instead of DISCORD_WEBHOOK_ID in the env variables. Changed per recommendation to make it easier for users. I can change it back also if you prefer not to have url in the vars, not sure if I misunderstood the suggestion was only for readme or not.

image

Saving Backup:

PS D:\repo\palworld-server-docker> docker exec -it palworld-server backup
Sending Discord json: {"embeds":[{"title":"Creating backup...","color":15258703}]}
Complete Save
Creating backup
Backup created at /palworld/backups/palworld-save-2024-02-05_21-30-13.tar.gz
Sending Discord json: {"embeds":[{"title":"Backup created at /palworld/backups/palworld-save-2024-02-05_21-30-13.tar.gz","color":52224}]}

I do not have an update, so was not able to test updates, I can add a message for already up to date, but that might be too spammy with autoupdate crons now being a thing.

PS D:\repo\palworld-server-docker> docker exec -it palworld-server update
The Server is up to date!

v4de avatar Feb 05 '24 21:02 v4de

Ok its working for me now, all the conditions were still checking for ID. Pull latest and use DISCORD_WEBHOOK_URL now instead of DISCORD_WEBHOOK_ID in the env variables. Changed per recommendation to make it easier for users. I can change it back also if you prefer not to have url in the vars, not sure if I misunderstood the suggestion was only for readme or not.

image

Saving Backup:

PS D:\repo\palworld-server-docker> docker exec -it palworld-server backup
Sending Discord json: {"embeds":[{"title":"Creating backup...","color":15258703}]}
Complete Save
Creating backup
Backup created at /palworld/backups/palworld-save-2024-02-05_21-30-13.tar.gz
Sending Discord json: {"embeds":[{"title":"Backup created at /palworld/backups/palworld-save-2024-02-05_21-30-13.tar.gz","color":52224}]}

I do not have an update, so was not able to test updates, I can add a message for already up to date, but that might be too spammy with autoupdate crons now being a thing.

PS D:\repo\palworld-server-docker> docker exec -it palworld-server update
The Server is up to date!

I agree repeatedly stating an update is available is excessive. Take a look at #209 to see how to trick the update script into updating.

Dashboy1998 avatar Feb 05 '24 23:02 Dashboy1998

I agree repeatedly stating an update is available is excessive. Take a look at #209 to see how to trick the update script into updating.

Cool that worked and got the update warning!

image

v4de avatar Feb 06 '24 01:02 v4de