Open codegain opened 3 weeks ago
You could use the the rcon protocol to check for that, I wrote an update script a long time ago, which also included the manually building the container (this is no longer necessary): auto-update The rcon client used in the script is this one: rcon But any other rcon client should also work
@tripplet Thanks! I will give that a try and report back with my script (if anyone else wants this too)
Yes, an "Auto-update if no one is online" feature would be a great addition. Currently, stable updates are being released rapidly. While this pace might slow down in the future, another DLC or major update could bring back the same problem. To future-proof this project, it would be ideal to implement this feature.
At the moment, I have a Watchtower instance that updates the server at 4:00 AM, assuming no players are online. I also have a Watchtower container that runs only once when I boot it, allowing for a quick instant update. However, having a feature that checks if all players have left the server before updating would be ideal. Optionally, it could include a maximum delay, like 24 hours, before forcibly kicking players to update the server.
For now, please share the scripts you have so I can set up a better system on my machine.
I would like to have something like this. The only question I would have is how this could be added, because it should not be part of the image, but something like a sidecar. The simples option would be something that controls the https://github.com/factoriotools/factorio-docker/blob/master/docker/docker-compose.yml deployment. But that would be quite static for docker compose only users, but at least a good start.
The container already contains an update script that runs when starting https://github.com/factoriotools/factorio-docker/blob/master/update.sh. A couple ways this could be done, some sort of cron script that is ran every X time. Supervisord etc.
I'd be interested in this as well, there is constant patches so it has to be updated all the time.
@jessielw This script is not part of the container. It is only used for the updater which checks for new versions then build new docker images based on it.
Ah I see that now. Certainly this could be resolved with Supervisord/SteamCMD or cron with basic scripts.
Some progress from my side:
I found https://github.com/gorcon/rcon-cli which can be installed via docker and executed via docker run
as running this factorio server already presumes that you have docker installed (but there would also be a binary available).
To get the currently online players I use this command:
docker run -it --rm outdead/rcon ./rcon -a 172.17.0.2:27015 -p $(cat /opt/factorio/config/rconpw) /players | grep -i online
if [ $? -eq 0 ]; then
echo " Found active players. Exit"
exit
else
echo " No active players"
fi
There are multiple requirements for this to work:
-p 27015:27015/tcp
)/opt/factorio/config/rconpw
which is the factorio installation directory + /config/rconpwThe command (without | grep -i online
) will give you a list of all players:
Players (2):
PlayerA
PlayerB
If there is a player online:
Players (2):
PlayerA
PlayerB (online)
the grep
only exists with an exit code of 0
if online
could be found and would not run the rest of you upgrade script.
(Thanks @tripplet for your script above)
Some help would be appricated:
factoriotools/factorio:stable
available - because we don't want to shutdown the server every couple of hours just because there is no one online. I tried with docker inspect
to get the digest and curl
to fetch infos from Docker Hub - but apparently the digest is the index digest
and Docker Hub only published image digests in their /tags
endpoint.EDIT:
Requires jq
to be installed and the name of the container to be factorio
docker inspect factorio | jq -r '.[].NetworkSettings.Networks.bridge.IPAddress'
and RCON PORT with docker inspect factorio | jq -r '.[].Config.Env[] | select(. | contains ("RCON_PORT"))' | awk -F= '{print $2}'
docker inspect factorio | jq -r '.[].Mounts.[].Source'
This is currently what I came up with:
#!/bin/sh
# configure
IMAGE_NAME="factoriotools/factorio"
TAG_NAME="stable"
CONTAINER_NAME="factorio"
# END configure
echo "Updating factorio..."
LOCAL_DIGEST=$(docker images --digests --no-trunc | grep $IMAGE_NAME | grep $TAG_NAME | awk '{print $3}')
REMOTE_DIGEST=$(curl -s "https://hub.docker.com/v2/repositories/$IMAGE_NAME/tags/$TAG_NAME/" | jq -r '.digest')
if [ "$LOCAL_DIGEST" = "$REMOTE_DIGEST" ]; then
echo " No update available for $IMAGE_NAME:$TAG_NAME ($LOCAL_DIGEST == $REMOTE_DIGEST)"
echo " Exit"
exit
else
echo " Update for $TAG_NAME available!"
fi
echo "Checking if any player is online..."
IP_ADDRESS=$(docker inspect $CONTAINER_NAME | jq -r '.[].NetworkSettings.Networks.bridge.IPAddress')
RCON_PORT=$(docker inspect $CONTAINER_NAME | jq -r '.[].Config.Env[] | select(. | contains ("RCON_PORT"))' | awk -F= '{print $2}')
MOUNT=$(docker inspect $CONTAINER_NAME | jq -r '.[].Mounts.[].Source')
echo " for container $CONTAINER_NAME (rcon $IP_ADDRESS:$RCON_PORT) at $MOUNT"
docker run -it --rm outdead/rcon ./rcon -a $IP_ADDRESS:$RCON_PORT -p $(cat $MOUNT/config/rconpw) /players | grep -i "(online)"
if [ $? -eq 0 ]; then
echo " Found online players. Exit"
exit
else
echo " No online players"
fi
echo "Continue to upgrade..."
# server is ready for update - run you update logic here
# f.e.
# docker stop factorio
# docker rm factorio
# docker pull factoriotools/factorio
# sudo docker run -d -p 34197:34197/udp -p 27015:27015/tcp -v /opt/factorio:/factorio --name factorio --restart=unless-stopped factoriotools/factorio:stable
index digest
found f.e. here https://hub.docker.com/layers/factoriotools/factorio/stable/images/sha256-713e8fdedd713f44022f0e0a0b01199c5e243ad7df082922c0e6ccabd9b980d0?context=explore)outdead/rcon
to connect to the IP:PORT and read the rcon password from the config/rconpw
fileThe script in this state does only check and not update the container (if you haven't commented out the last lines) just to test if it works for your given setup.
This could be executed by a cron on the host to periodically check if there is an update available and update the server if no player is online.
Arg I also finally found some time today 😄
My idea was to add an rcon client to all factorio images. This is a very minimal c implementation, just 200 lines C code without any dependencies (the result binary is only ~34kB).
The rcon implementation is tailored for this purpose, no option to set a host, port or password. All required values pulled from the factorio images environment variables.
It is only there to send commands to the running factorio server inside the same container and read the response.
To use it simply run
docker exec running-factorio-container rcon ARGUMENTS
For example:
docker exec factorio rcon /players
or docker exec factorio rcon /promote SomePlayer
I think this is a nice addition in general, outside of the use for updating as a build-in way to talk to the factorio server, for example in scripts.
I also added a simple script which checks for the active player count. Using that it should be possible to leverage the pre-update hook of watchtower: https://containrrr.dev/watchtower/lifecycle-hooks/
I have not tested that part yet, but wanted to post it now to combine our efforts.
See the following pull request
@tripplet Awesome! That would massively simplify a manual updating script to
#!/bin/sh
# configure
IMAGE_NAME="factoriotools/factorio"
TAG_NAME="stable"
CONTAINER_NAME="factorio"
# END configure
echo "Updating factorio..."
LOCAL_DIGEST=$(docker images --digests --no-trunc | grep $IMAGE_NAME | grep $TAG_NAME | awk '{print $3}')
REMOTE_DIGEST=$(curl -s "https://hub.docker.com/v2/repositories/$IMAGE_NAME/tags/$TAG_NAME/" | jq -r '.digest')
if [ "$LOCAL_DIGEST" = "$REMOTE_DIGEST" ]; then
echo " No update available for $IMAGE_NAME:$TAG_NAME ($LOCAL_DIGEST == $REMOTE_DIGEST)"
echo " Exit"
exit
else
echo " Update for $TAG_NAME available!"
fi
echo "Checking if any player is online..."
docker exec $CONTAINER_NAME rcon /players | grep -i "(online)"
if [ $? -eq 0 ]; then
echo " Found online players. Exit"
exit
else
echo " No online players"
fi
echo "Continue to upgrade..."
# server is ready for update - run you update logic here
# f.e.
# docker stop factorio
# docker rm factorio
# docker pull factoriotools/factorio
# sudo docker run -d -p 34197:34197/udp -p 27015:27015/tcp -v /opt/factorio:/factorio --name factorio --restart=unless-stopped factoriotools/factorio:stable
and possibly remove the need to expose the RCON port as this is all done within the container, right? Or just using watchtower and let it handle the upgrade with a pre-update hook.
Nice script. I think both are valid approaches maybe someone does not want to have a watchtower container running the whole time just to check for updates and just have a simple cron job script which runs when the want it to or trigger an update manually using this script.
Hi,
I'm looking for a way to upgrade the server to the latest "stable" tag when no player is online. My server is configured to pause the game if no player is online. If I'm not at home, my friends sometimes have to downgrade their factorio version to an older version because the server isn't upgraded yet.
I have an .sh file to automatically backup the save, shut down the container, upgrade it and start it again. I haven't found a way to fully automate this to upgrade the server if no one is online.
I could use a cronjob, but this would disrupt the gameplay if a player is online at that time.
Is there a way to read periodically if some player is online and if not, upgrade the server to a new version like once per hour maybe (or to start my custom script)?