From ac3af477f030d116d02a41f1ef2db8400d4009b7 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:23:40 -0400 Subject: [PATCH 01/34] Fix debian postinst script --- build/package/deb/debian/postinst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 4f6d808f98e..0c1b0975c5f 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,12 +1,12 @@ #!/bin/sh -e -if [[ "$1" = "configure" ]]; then +if [ "$1" = "configure" ]; then systemctl mask tgstation-server fi #DEBHELPER# -if [[ "$1" = "configure" ]]; then +if [ "$1" = "configure" ]; then echo " _ _ _ _ " echo " | |_ __ _ ___| |_ __ _| |_(_) ___ _ __ ___ ___ _ ____ _____ _ __ " echo " | __/ _` / __| __/ _` | __| |/ _ \| '_ \ _____/ __|/ _ \ '__\ \ / / _ \ '__|" From f40d85c286f04331f84e32ae0501c87fc3045b79 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:27:59 -0400 Subject: [PATCH 02/34] Use deb-systemd-invoke --- build/package/deb/debian/postinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 0c1b0975c5f..caf51f19b02 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,7 +1,7 @@ #!/bin/sh -e if [ "$1" = "configure" ]; then - systemctl mask tgstation-server + deb-systemd-invoke mask tgstation-server fi #DEBHELPER# From aac1fbb069e15930d988fcb4a23d419a34b1abfd Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:40:08 -0400 Subject: [PATCH 03/34] Do not package platform executable artifacts --- .github/workflows/ci-suite.yml | 1 + build/package/deb/debian/rules | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/ci-suite.yml b/.github/workflows/ci-suite.yml index c66fc28fb0e..0f88ac92116 100644 --- a/.github/workflows/ci-suite.yml +++ b/.github/workflows/ci-suite.yml @@ -566,6 +566,7 @@ jobs: dotnet publish -c ${{ matrix.configuration }}NoService --no-build -o ../../Artifacts/Console/lib/Default mv ../../Artifacts/Console/lib/Default/appsettings.yml ../../Artifacts/Console/appsettings.yml rm ../../Artifacts/Console/lib/Default/Tgstation.Server.Host + rm ../../Artifacts/Console/Tgstation.Server.Host.Console - name: Package Server Update Package if: ${{ matrix.configuration == 'Release' && matrix.watchdog-type == 'System' && matrix.database-type == 'PostgresSql' }} diff --git a/build/package/deb/debian/rules b/build/package/deb/debian/rules index d09702f2ddf..8e185ba247b 100755 --- a/build/package/deb/debian/rules +++ b/build/package/deb/debian/rules @@ -15,6 +15,7 @@ override_dh_auto_build: cd src/Tgstation.Server.Host && dotnet publish -c Release -o ../../artifacts/lib/Default mv artifacts/lib/Default/appsettings.yml artifacts/appsettings.yml rm artifacts/lib/Default/Tgstation.Server.Host + rm artifacts/Tgstation.Server.Host.Console override_dh_auto_install: cp build/package/deb/MakeInstall ./Makefile From 78c425ee125465e9bc7576d9d69d44d98193543e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:41:21 -0400 Subject: [PATCH 04/34] Set -e in `tgs.sh` --- src/Tgstation.Server.Host.Console/tgs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host.Console/tgs.sh b/src/Tgstation.Server.Host.Console/tgs.sh index bf195f8e759..53314d3fc95 100755 --- a/src/Tgstation.Server.Host.Console/tgs.sh +++ b/src/Tgstation.Server.Host.Console/tgs.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e script_full_path=$(dirname "$0") exec dotnet "$script_full_path/Tgstation.Server.Host.Console.dll" "$@" From 6f167a179436348f0d2caed9b00e390ccd4850c6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:41:36 -0400 Subject: [PATCH 05/34] Add a newline for readibility --- src/Tgstation.Server.Host.Console/tgs.bat | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Tgstation.Server.Host.Console/tgs.bat b/src/Tgstation.Server.Host.Console/tgs.bat index 39a4cfc04f3..ebbd41d058a 100644 --- a/src/Tgstation.Server.Host.Console/tgs.bat +++ b/src/Tgstation.Server.Host.Console/tgs.bat @@ -1,2 +1,3 @@ @echo off + dotnet %~dp0Tgstation.Server.Host.Console.dll %* From 1b4d392b3d59f021b49fbc9dfd2cf6ee490b86d4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:49:52 -0400 Subject: [PATCH 06/34] Use literal backslashes in intro banner --- build/package/deb/debian/postinst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index caf51f19b02..8804bb2b851 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -9,9 +9,9 @@ fi if [ "$1" = "configure" ]; then echo " _ _ _ _ " echo " | |_ __ _ ___| |_ __ _| |_(_) ___ _ __ ___ ___ _ ____ _____ _ __ " - echo " | __/ _` / __| __/ _` | __| |/ _ \| '_ \ _____/ __|/ _ \ '__\ \ / / _ \ '__|" - echo " | || (_| \__ \ || (_| | |_| | (_) | | | |_____\__ \ __/ | \ V / __/ | " - echo " \__\__, |___/\__\__,_|\__|_|\___/|_| |_| |___/\___|_| \_/ \___|_| " + echo " | __/ _` / __| __/ _` | __| |/ _ \\| '_ \\ _____/ __|/ _ \\ '__\\ \\ / / _ \\ '__|" + echo " | || (_| \\__ \\ || (_| | |_| | (_) | | | |_____\\__ \\ __/ | \\ V / __/ | " + echo " \\__\\__, |___/\\__\\__,_|\\__|_|\\___/|_| |_| |___/\\___|_| \\_/ \\___|_| " echo " |___/ " echo "tgstation-server is now installed but must first be configured" echo "Run 'sudo tgs-configure' to interactively configure your server" From 3f9dcf7103665fb652227a21ac22b46f6852de82 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 08:57:01 -0400 Subject: [PATCH 07/34] Use deb-systemd-helper --- build/package/deb/debian/postinst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 8804bb2b851..afca462c7d3 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,7 +1,8 @@ #!/bin/sh -e if [ "$1" = "configure" ]; then - deb-systemd-invoke mask tgstation-server + # disable first time startup so user can configure + deb-systemd-helper mask 'tgstation-server.service' >/dev/null || true fi #DEBHELPER# From 9db41ee8ee29b78a71d2a9fc592d64c8fbf41dc2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 09:00:14 -0400 Subject: [PATCH 08/34] Use WATCHDOG=1 as initial sd_notify command --- src/Tgstation.Server.Host/System/SystemDManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 5dd66e259ea..a026be25fb6 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -104,7 +104,7 @@ public Task HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWit /// public Task StartAsync(CancellationToken cancellationToken) { - if (SendSDNotify("RELOADING=1")) + if (SendSDNotify("WATCHDOG=1")) { logger.LogDebug("SystemD detected"); runTask = RunAsync(watchdogCts.Token); From 6b1aad68e07996fb895557f4584076de89ba2d25 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 09:02:07 -0400 Subject: [PATCH 09/34] Code deduplication --- src/Tgstation.Server.Host/System/SystemDManager.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index a026be25fb6..44ea899b3ff 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -19,6 +19,11 @@ namespace Tgstation.Server.Host.System /// sealed class SystemDManager : IHostedService, IRestartHandler, IDisposable { + /// + /// The sd_notify command for notifying the watchdog we are alive. + /// + const string SDNotifyWatchdog = "WATCHDOG=1"; + /// /// The for the . /// @@ -104,7 +109,7 @@ public Task HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWit /// public Task StartAsync(CancellationToken cancellationToken) { - if (SendSDNotify("WATCHDOG=1")) + if (SendSDNotify(SDNotifyWatchdog)) { logger.LogDebug("SystemD detected"); runTask = RunAsync(watchdogCts.Token); @@ -176,10 +181,7 @@ void CheckReady() { await Task.Delay(milliseconds, cancellationToken); - logger.LogTrace("Sending sd_notify WATCHDOG=1"); - var result = NativeMethods.sd_notify(0, "WATCHDOG=1"); - if (result <= 0) - logger.LogError(new UnixIOException(result), "sd_notify READY=1 failed!"); + SendSDNotify(SDNotifyWatchdog); } } catch (OperationCanceledException ex) From 257f462960046ab612df7596c8f8140d7c7c1d7d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 09:07:42 -0400 Subject: [PATCH 10/34] Fix issues with installing configuration --- build/package/deb/MakeInstall | 3 +-- build/package/deb/appsettings.Initial.yml | 2 ++ tgstation-server.sln | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 build/package/deb/appsettings.Initial.yml diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index 982f06b80a1..4f53ef641d4 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -4,8 +4,7 @@ install: install -d $(DESTDIR)/opt/tgstation-server cp -r artifacts/* $(DESTDIR)/opt/tgstation-server install -d $(DESTDIR)/etc/tgstation-server - cp artifacts/appsettings.yml $(DESTDIR)/etc/tgstation-server/appsettings.ex.yml - echo -e "# tgstation-server configuration file\n# See /etc/tgstation-server/appsettings.ex.yml for details on individual configuration options" > $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml + install build/package/deb/appsettings.Initial.yml $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml dh_link $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml $(DESTDIR)/opt/tgstation-server/appsettings.Production.yml install -d $(DESTDIR)/usr/bin install build/package/deb/tgs-configure $(DESTDIR)/usr/bin/ diff --git a/build/package/deb/appsettings.Initial.yml b/build/package/deb/appsettings.Initial.yml new file mode 100644 index 00000000000..575df3fd32f --- /dev/null +++ b/build/package/deb/appsettings.Initial.yml @@ -0,0 +1,2 @@ +# tgstation-server configuration file +# See /opt/tgstation-server/appsettings.yml for details on individual configuration options diff --git a/tgstation-server.sln b/tgstation-server.sln index e7206b2cd21..fb73c96e355 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -204,6 +204,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "package", "package", "{2648 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deb", "deb", "{457A1F89-6201-4430-BCC6-2F4438A54B9E}" ProjectSection(SolutionItems) = preProject + build\package\deb\appsettings.Initial.yml = build\package\deb\appsettings.Initial.yml build\package\deb\build_package.sh = build\package\deb\build_package.sh build\package\deb\MakeInstall = build\package\deb\MakeInstall build\package\deb\tgs-configure = build\package\deb\tgs-configure From f8127db2c6d89830bb6b877df1d36e00e01e01ca Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 09:25:57 -0400 Subject: [PATCH 11/34] `uninstall` is completely unnecessary here --- build/package/deb/MakeInstall | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index 4f53ef641d4..fca542545b4 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -8,7 +8,3 @@ install: dh_link $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml $(DESTDIR)/opt/tgstation-server/appsettings.Production.yml install -d $(DESTDIR)/usr/bin install build/package/deb/tgs-configure $(DESTDIR)/usr/bin/ - -uninstall: - mkdir -p $(DESTDIR)/opt/tgstation-server - cp -r artifacts/* $(DESTDIR)/opt/tgstation-server/ From 0a89cdd95d81d3e2fd7b50d5b2c14c25f87e47a4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 09:51:28 -0400 Subject: [PATCH 12/34] Use recursive `install` --- build/package/deb/MakeInstall | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index fca542545b4..2e9b248a203 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -2,7 +2,7 @@ install: install -d $(DESTDIR)/opt/tgstation-server - cp -r artifacts/* $(DESTDIR)/opt/tgstation-server + cd artifacts && for f in $(find .); do install "$f" $(DESTDIR)/opt/tgstation-server/; done install -d $(DESTDIR)/etc/tgstation-server install build/package/deb/appsettings.Initial.yml $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml dh_link $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml $(DESTDIR)/opt/tgstation-server/appsettings.Production.yml From 0ac3966bc4655fc558e44d4c18031f1729a57226 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 11:01:15 -0400 Subject: [PATCH 13/34] Clean up configure script --- build/package/deb/tgs-configure | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/build/package/deb/tgs-configure b/build/package/deb/tgs-configure index 05546f2a637..5becb6a0362 100755 --- a/build/package/deb/tgs-configure +++ b/build/package/deb/tgs-configure @@ -1,5 +1,4 @@ #!/bin/sh -pushd /opt/tgstation-server -dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll General:SetupWizardMode=Only -popd +cd /opt/tgstation-server +exec dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll General:SetupWizardMode=Only From d5cd222800766f3e492430e5fe598d2546a87463 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 11:04:26 -0400 Subject: [PATCH 14/34] Update the README with `tgs-configure` for Linux --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eee581a72c6..bb07b4281e5 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ Older server versions can be found in the V# branches of this repository. Note t ### Pre-Requisites -- [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0) (Choose the option to `Run Server Apps` for your system) If you plan to install tgstation-server as a Windows service, you should also ensure that your .NET Framework runtime version is >= v4.7.2 (Download can be found on same page). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server). - A [MariaDB](https://downloads.mariadb.org/), MySQL, [PostgresSQL](https://www.postgresql.org/download/), or [Microsoft SQL Server](https://www.microsoft.com/en-us/download/details.aspx?id=55994) database engine is required ### Installation @@ -27,6 +26,8 @@ Follow the instructions for your OS below. #### Windows +Download and install the [ASP .NET Core Runtime (>= v6.0)](https://dotnet.microsoft.com/download/dotnet/6.0) (Choose the option to `Run Server Apps` for your system). If you plan to install tgstation-server as a Windows service, you should also ensure that your .NET Framework runtime version is >= v4.7.2 (Most modern systems have it by default. Download can be found on same page). Ensure that the `dotnet` executable file is in your system's `PATH` variable (or that of the user's that will be running the server), you can test this by opening a command prompt and running `dotnet --list-runtimes`. + [Download the latest release .zip](https://github.com/tgstation/tgstation-server/releases/latest). You probably want the `ServerService` package. Choose `ServerConsole` if you prefer not to use the Windows service. Extract the .zip file to where you want the server to run from. Note the account running the server must have write and delete access to the `lib` subdirectory. @@ -43,7 +44,7 @@ Installing natively is the recommended way to run tgstation-server on Linux. ##### Ubuntu -Install TGS and all it's dependencies via our apt repository with this one-liner: +Install TGS and all it's dependencies via our apt repository, interactively configure it, and start the service with this one-liner: ```sh sudo dpkg --add-architecture i386 \ @@ -52,7 +53,9 @@ sudo dpkg --add-architecture i386 \ && sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv B6FD15EE7ED77676EAEAF910EEEDC8280A307527 \ && sudo add-apt-repository -y "deb https://tgstation.github.io/tgstation-ppa/debian unstable main" \ && sudo apt update \ -&& sudo apt install -y tgstation-server +&& sudo apt install -y tgstation-server \ +&& sudo tgs-configure \ +&& sudo systemctl start tgstation-server ``` ##### Debian From 424659301f0de2d4fc455b28cade2478514e795f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 11:19:44 -0400 Subject: [PATCH 15/34] Fix install header again --- build/package/deb/debian/postinst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index afca462c7d3..59b7e749960 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -10,7 +10,7 @@ fi if [ "$1" = "configure" ]; then echo " _ _ _ _ " echo " | |_ __ _ ___| |_ __ _| |_(_) ___ _ __ ___ ___ _ ____ _____ _ __ " - echo " | __/ _` / __| __/ _` | __| |/ _ \\| '_ \\ _____/ __|/ _ \\ '__\\ \\ / / _ \\ '__|" + echo " | __/ _\` / __| __/ _\` | __| |/ _ \\| '_ \\ _____/ __|/ _ \\ '__\\ \\ / / _ \\ '__|" echo " | || (_| \\__ \\ || (_| | |_| | (_) | | | |_____\\__ \\ __/ | \\ V / __/ | " echo " \\__\\__, |___/\\__\\__,_|\\__|_|\\___/|_| |_| |___/\\___|_| \\_/ \\___|_| " echo " |___/ " From 647ed308bb57c26688cbe0d64077213598ee65c6 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 13:37:16 -0400 Subject: [PATCH 16/34] Fully support `notify-reload` --- build/tgstation-server.service | 3 ++- .../System/NativeMethods.cs | 17 ++++++++++++ .../System/SystemDManager.cs | 26 ++++++++++++++++--- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/build/tgstation-server.service b/build/tgstation-server.service index 21c68093725..5eeff9569a2 100644 --- a/build/tgstation-server.service +++ b/build/tgstation-server.service @@ -7,12 +7,13 @@ After=postgresql.service After=mssql-server.service [Service] -Type=notify +Type=notify-reload NotifyAccess=all ExecStart=/bin/bash /opt/tgstation-server/tgs.sh General:SetupWizardMode=Never TimeoutStartSec=600 Restart=Always KillMode=process +ReloadSignal=SIGUSR2 RestartKillSignal=SIGUSR2 AmbientCapabilities=CAP_SYS_NICE StandardOutput=null diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index dacb4351bcd..425ce687971 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -2,6 +2,8 @@ using System.Runtime.InteropServices; using System.Text; +using Mono.Unix.Native; + namespace Tgstation.Server.Host.System { /// @@ -44,6 +46,14 @@ public enum MiniDumpType : uint WithThreadInfo = 0x00001000, } + /// + /// See https://linux.die.net/man/3/clock_gettime. + /// + public enum ClockId : int + { + CLOCK_MONOTONIC = 1, // from linux/time.h. God forbid this breaks uncannily + } + /// /// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowthreadprocessid. /// @@ -137,5 +147,12 @@ public static extern bool MiniDumpWriteDump( public static extern int sd_notify(int unset_environment, [MarshalAs(UnmanagedType.LPUTF8Str)] string state); #pragma warning restore CA2101 #pragma warning restore IDE0079 + + /// + /// See https://linux.die.net/man/3/clock_gettime. + /// + /// We're relying on the portablility of for this to work. Untested on x86, but I don't think that's supported anymore? + [DllImport("libc", SetLastError = true)] + public static extern int clock_gettime(ClockId clk_id, out Timeval tp); } } diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 44ea899b3ff..60ab8c39742 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using Mono.Unix; +using Mono.Unix.Native; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Core; @@ -153,10 +154,27 @@ void CheckReady() applicationLifetime.ApplicationStarted.Register(() => CheckReady()); applicationLifetime.ApplicationStopping.Register( - () => SendSDNotify( - restartInProgress - ? "RELOADING=1" - : "STOPPING=1")); + () => + { + string command; + if (restartInProgress) + { + if (NativeMethods.clock_gettime(NativeMethods.ClockId.CLOCK_MONOTONIC, out var tp) != 0) + { + logger.LogError(new UnixIOException(Stdlib.GetLastError()), "clock_gettime failed!"); + command = "RELOADING=1"; // SystemD can cope + } + else + { + const long SecondsToNanoSeconds = 1000000000; // https://github.com/dotnet/runtime/blob/0f71880d79fc027dd2c0f8c83113af0ad0bb6f55/src/native/libs/System.Native/pal_time.c#L22C5-L22C38 + command = $"RELOADING=1\nMONOTONIC_USEC={(tp.tv_sec * SecondsToNanoSeconds) + tp.tv_usec}"; + } + } + else + command = "STOPPING=1"; + + SendSDNotify(command); + }); try { From 6b4c876746ba05774fccad0eee3127fa8c1eb25f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 13:37:41 -0400 Subject: [PATCH 17/34] Fix install commands --- build/package/deb/MakeInstall | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index 2e9b248a203..5326c67b239 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -1,10 +1,10 @@ #!/usr/bin/make -f install: - install -d $(DESTDIR)/opt/tgstation-server - cd artifacts && for f in $(find .); do install "$f" $(DESTDIR)/opt/tgstation-server/; done - install -d $(DESTDIR)/etc/tgstation-server - install build/package/deb/appsettings.Initial.yml $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml - dh_link $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml $(DESTDIR)/opt/tgstation-server/appsettings.Production.yml - install -d $(DESTDIR)/usr/bin - install build/package/deb/tgs-configure $(DESTDIR)/usr/bin/ + install -d "$(DESTDIR)/opt/tgstation-server" + cd artifacts && for f in $(find .); do install "$f" "$(DESTDIR)/opt/tgstation-server/$f"; done + install -d "$(DESTDIR)/etc/tgstation-server" + install build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" + ln -s $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml "$(DESTDIR)/opt/tgstation-server/appsettings.Production.yml" + install -d "$(DESTDIR)/usr/bin" + install build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/" From 065968e31d3ad10a4277bf328b8353fac3fbe382 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 13:41:05 -0400 Subject: [PATCH 18/34] Nuget Package updates --- .../Tgstation.Server.Host.csproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj index ef8f42a56e2..a9e8b356526 100644 --- a/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj +++ b/src/Tgstation.Server.Host/Tgstation.Server.Host.csproj @@ -79,20 +79,20 @@ - + - + - + - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + - + @@ -100,7 +100,7 @@ - + @@ -112,7 +112,7 @@ - + From c43d95142f7fa1d8c265a8d394ecae6cc2f6ef8f Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 13:50:00 -0400 Subject: [PATCH 19/34] Escape Makefile escaping --- build/package/deb/MakeInstall | 2 +- build/package/deb/install_artifacts.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100755 build/package/deb/install_artifacts.sh diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index 5326c67b239..dff34a53ac7 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -2,7 +2,7 @@ install: install -d "$(DESTDIR)/opt/tgstation-server" - cd artifacts && for f in $(find .); do install "$f" "$(DESTDIR)/opt/tgstation-server/$f"; done + build/package/deb/install_artifacts.sh "$(DESTDIR)" install -d "$(DESTDIR)/etc/tgstation-server" install build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" ln -s $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml "$(DESTDIR)/opt/tgstation-server/appsettings.Production.yml" diff --git a/build/package/deb/install_artifacts.sh b/build/package/deb/install_artifacts.sh new file mode 100755 index 00000000000..daa17033cc0 --- /dev/null +++ b/build/package/deb/install_artifacts.sh @@ -0,0 +1,3 @@ +#!/usr/bin/sh -e + +cd artifacts && for f in $(find .); do install "$f" "$1/opt/tgstation-server/$f"; done From 5fffe501a22efab97b088ed33bab90e316666736 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 14:31:28 -0400 Subject: [PATCH 20/34] CLOCK_MONOTONIC is a non-portable native define... Use a hacky Stopwatch value instead --- .../System/NativeMethods.cs | 17 ---------- .../System/SystemDManager.cs | 33 +++++++------------ 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/Tgstation.Server.Host/System/NativeMethods.cs b/src/Tgstation.Server.Host/System/NativeMethods.cs index 425ce687971..dacb4351bcd 100644 --- a/src/Tgstation.Server.Host/System/NativeMethods.cs +++ b/src/Tgstation.Server.Host/System/NativeMethods.cs @@ -2,8 +2,6 @@ using System.Runtime.InteropServices; using System.Text; -using Mono.Unix.Native; - namespace Tgstation.Server.Host.System { /// @@ -46,14 +44,6 @@ public enum MiniDumpType : uint WithThreadInfo = 0x00001000, } - /// - /// See https://linux.die.net/man/3/clock_gettime. - /// - public enum ClockId : int - { - CLOCK_MONOTONIC = 1, // from linux/time.h. God forbid this breaks uncannily - } - /// /// See https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-getwindowthreadprocessid. /// @@ -147,12 +137,5 @@ public static extern bool MiniDumpWriteDump( public static extern int sd_notify(int unset_environment, [MarshalAs(UnmanagedType.LPUTF8Str)] string state); #pragma warning restore CA2101 #pragma warning restore IDE0079 - - /// - /// See https://linux.die.net/man/3/clock_gettime. - /// - /// We're relying on the portablility of for this to work. Untested on x86, but I don't think that's supported anymore? - [DllImport("libc", SetLastError = true)] - public static extern int clock_gettime(ClockId clk_id, out Timeval tp); } } diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index 60ab8c39742..a9a621b7e0b 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -7,7 +7,6 @@ using Microsoft.Extensions.Logging; using Mono.Unix; -using Mono.Unix.Native; using Tgstation.Server.Host.Components; using Tgstation.Server.Host.Core; @@ -60,6 +59,13 @@ sealed class SystemDManager : IHostedService, IRestartHandler, IDisposable /// bool restartInProgress; + /// + /// Get the current total nanoseconds value of the CLOCK_MONOTONIC clock. + /// + /// A representing the clock time in nanoseconds. + /// See https://linux.die.net/man/3/clock_gettime. + static long GetMonotonicUsec() => global::System.Diagnostics.Stopwatch.GetTimestamp(); // HACK: https://github.com/dotnet/runtime/blob/v6.0.19/src/libraries/Native/Unix/System.Native/pal_time.c#L51 clock_gettime_nsec_np is an OSX only thing apparently... + /// /// Initializes a new instance of the class. /// @@ -154,27 +160,10 @@ void CheckReady() applicationLifetime.ApplicationStarted.Register(() => CheckReady()); applicationLifetime.ApplicationStopping.Register( - () => - { - string command; - if (restartInProgress) - { - if (NativeMethods.clock_gettime(NativeMethods.ClockId.CLOCK_MONOTONIC, out var tp) != 0) - { - logger.LogError(new UnixIOException(Stdlib.GetLastError()), "clock_gettime failed!"); - command = "RELOADING=1"; // SystemD can cope - } - else - { - const long SecondsToNanoSeconds = 1000000000; // https://github.com/dotnet/runtime/blob/0f71880d79fc027dd2c0f8c83113af0ad0bb6f55/src/native/libs/System.Native/pal_time.c#L22C5-L22C38 - command = $"RELOADING=1\nMONOTONIC_USEC={(tp.tv_sec * SecondsToNanoSeconds) + tp.tv_usec}"; - } - } - else - command = "STOPPING=1"; - - SendSDNotify(command); - }); + () => SendSDNotify( + restartInProgress + ? $"RELOADING=1\nMONOTONIC_USEC={GetMonotonicUsec()}" + : "STOPPING=1")); try { From 5d9115100f17e72dc8e90a3e53ef2cbe2ea8d91c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 14:38:04 -0400 Subject: [PATCH 21/34] `*` instead of `.` in find command --- build/package/deb/install_artifacts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/install_artifacts.sh b/build/package/deb/install_artifacts.sh index daa17033cc0..9375eff83e1 100755 --- a/build/package/deb/install_artifacts.sh +++ b/build/package/deb/install_artifacts.sh @@ -1,3 +1,3 @@ #!/usr/bin/sh -e -cd artifacts && for f in $(find .); do install "$f" "$1/opt/tgstation-server/$f"; done +cd artifacts && for f in $(find *); do install "$f" "$1/opt/tgstation-server/$f"; done From 3defb4945016d457810bf01362bef157d35a32d4 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 14:51:41 -0400 Subject: [PATCH 22/34] `find` only files --- build/package/deb/install_artifacts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/package/deb/install_artifacts.sh b/build/package/deb/install_artifacts.sh index 9375eff83e1..512447df477 100755 --- a/build/package/deb/install_artifacts.sh +++ b/build/package/deb/install_artifacts.sh @@ -1,3 +1,3 @@ #!/usr/bin/sh -e -cd artifacts && for f in $(find *); do install "$f" "$1/opt/tgstation-server/$f"; done +cd artifacts && for f in $(find * -type f); do install "$f" "$1/opt/tgstation-server/$f"; done From 7e1245f0bf0ce72159633886fce7dcc7a560e8ed Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 15:55:56 -0400 Subject: [PATCH 23/34] Fix creating deb directory structure --- build/package/deb/MakeInstall | 8 +++----- build/package/deb/install_artifacts.sh | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index dff34a53ac7..5fad7c1b850 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -1,10 +1,8 @@ #!/usr/bin/make -f install: - install -d "$(DESTDIR)/opt/tgstation-server" build/package/deb/install_artifacts.sh "$(DESTDIR)" - install -d "$(DESTDIR)/etc/tgstation-server" - install build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" - ln -s $(DESTDIR)/etc/tgstation-server/appsettings.Production.yml "$(DESTDIR)/opt/tgstation-server/appsettings.Production.yml" + install -D build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" + ln -s "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" "$(DESTDIR)/opt/tgstation-server/appsettings.Production.yml" install -d "$(DESTDIR)/usr/bin" - install build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/" + install -D build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/" diff --git a/build/package/deb/install_artifacts.sh b/build/package/deb/install_artifacts.sh index 512447df477..dead938fa24 100755 --- a/build/package/deb/install_artifacts.sh +++ b/build/package/deb/install_artifacts.sh @@ -1,3 +1,3 @@ #!/usr/bin/sh -e -cd artifacts && for f in $(find * -type f); do install "$f" "$1/opt/tgstation-server/$f"; done +cd artifacts && for f in $(find * -type f); do install -D "$f" "$1/opt/tgstation-server/$f"; done From 85f8c9131b1c731a760767a3c17cff7e736c83aa Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:07:05 -0400 Subject: [PATCH 24/34] Make new initial appsetting detect as empty --- src/Tgstation.Server.Host/Setup/SetupWizard.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/Setup/SetupWizard.cs b/src/Tgstation.Server.Host/Setup/SetupWizard.cs index 9db7a180634..15f2b82e483 100644 --- a/src/Tgstation.Server.Host/Setup/SetupWizard.cs +++ b/src/Tgstation.Server.Host/Setup/SetupWizard.cs @@ -1050,7 +1050,10 @@ async Task HandleSetupCancel() { var bytes = await ioManager.ReadAllBytes(userConfigFileName, cancellationToken); var contents = Encoding.UTF8.GetString(bytes); - var existingConfigIsEmpty = String.IsNullOrWhiteSpace(contents) || contents.Trim() == "{}"; + var lines = contents.Split('\n', StringSplitOptions.RemoveEmptyEntries); + var existingConfigIsEmpty = lines + .Select(line => line.Trim()) + .All(line => line[0] == '#' || line == "{}" || line.Length == 0); shouldRunBasedOnAutodetect = existingConfigIsEmpty; } else From bc5b5f9e96eca855b23adbdc852254081fc6784a Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:08:27 -0400 Subject: [PATCH 25/34] Fix Mono.Posix loading on Windows host watchdog --- .../SignalChecker.cs | 92 +++++++++++++++++++ .../Watchdog.cs | 89 ++++++------------ 2 files changed, 120 insertions(+), 61 deletions(-) create mode 100644 src/Tgstation.Server.Host.Watchdog/SignalChecker.cs diff --git a/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs b/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs new file mode 100644 index 00000000000..3be780fb392 --- /dev/null +++ b/src/Tgstation.Server.Host.Watchdog/SignalChecker.cs @@ -0,0 +1,92 @@ +using System; +using System.Threading; +using System.Threading.Tasks; + +using Microsoft.Extensions.Logging; + +using Mono.Unix; +using Mono.Unix.Native; + +namespace Tgstation.Server.Host.Watchdog +{ + /// + /// Helper for checking POSIX signals. + /// + static class SignalChecker + { + /// + /// Forwards certain signals to a given . + /// + /// The to write to. + /// The of the process to forward signals to. + /// The for the operation. + /// A representing the running operation. + public static async Task CheckSignals(ILogger logger, int childPid, CancellationToken cancellationToken) + { + var signalTcs = new TaskCompletionSource(); + async Task CheckSignal(Signum signum) + { + try + { + using var unixSignal = new UnixSignal(signum); + if (!unixSignal.IsSet) + { + logger.LogTrace("Waiting for {signum}...", signum); + while (!unixSignal.IsSet) + await Task.Delay(TimeSpan.FromMilliseconds(250), cancellationToken); + + logger.LogTrace("{signum} received!", signum); + } + else + logger.LogDebug("{signum} has already been sent", signum); + + signalTcs.TrySetResult(signum); + } + catch (OperationCanceledException) + { + } + + return signum; + } + + var tasks = new[] + { + CheckSignal(Signum.SIGUSR1), + CheckSignal(Signum.SIGUSR2), + }; + var completedTask = await Task.WhenAny(tasks); + if (cancellationToken.IsCancellationRequested) + { + await Task.WhenAll(tasks); + return; + } + + var signalReceived = await completedTask; + logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived); + var result = Syscall.kill(childPid, signalReceived.Value); + if (result != 0) + logger.LogWarning( + new UnixIOException(Stdlib.GetLastError()), + "Failed to forward {signalReceived}!", + signalReceived); + + // forward the other signal if necessary + await Task.WhenAll(tasks); + if (cancellationToken.IsCancellationRequested) + return; + + var otherTask = tasks[0] == completedTask + ? tasks[1] + : tasks[0]; + + signalReceived = await otherTask; + logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived); + result = Syscall.kill(childPid, signalReceived.Value); + if (result != 0) + logger.LogWarning( + new UnixIOException(Stdlib.GetLastError()), + "Failed to forward {signalReceived}!", + signalReceived); + } + } +} diff --git a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs index d8a1d580ed0..1afd2cad85b 100644 --- a/src/Tgstation.Server.Host.Watchdog/Watchdog.cs +++ b/src/Tgstation.Server.Host.Watchdog/Watchdog.cs @@ -11,9 +11,6 @@ using Microsoft.Extensions.Logging; -using Mono.Unix; -using Mono.Unix.Native; - using Tgstation.Server.Host.Common; namespace Tgstation.Server.Host.Watchdog @@ -71,7 +68,8 @@ public async Task RunAsync(bool runConfigure, string[] args, CancellationToken c { // VS special tactics // just copy the shit where it belongs - Directory.Delete(assemblyStoragePath, true); + if (Directory.Exists(assemblyStoragePath)) + Directory.Delete(assemblyStoragePath, true); Directory.CreateDirectory(defaultAssemblyPath); var sourcePath = "../../../../Tgstation.Server.Host/bin/Debug/net6.0"; @@ -128,8 +126,8 @@ public async Task RunAsync(bool runConfigure, string[] args, CancellationToken c if (runConfigure) { - logger.LogInformation("Running configuration check and wizard if necessary..."); - arguments.Add("General:SetupWizardMode=Only"); + logger.LogInformation("Running configuration check and wizard..."); + arguments.Add("--General:SetupWizardMode=Only"); } arguments.AddRange(args); @@ -179,61 +177,19 @@ public async Task RunAsync(bool runConfigure, string[] args, CancellationToken c })) { var processTask = tcs.Task; - while (!processTask.IsCompleted) + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + + var checkerTask = isWindows + ? Task.CompletedTask + : SignalChecker.CheckSignals(logger, childPid, cts.Token); + try { - var signalTcs = new TaskCompletionSource(); - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - async Task CheckSignal(Signum signum) - { - if (isWindows) - return; - - try - { - using var unixSignal = new UnixSignal(signum); - if (!unixSignal.IsSet) - { - logger.LogTrace("Waiting for {signum}...", signum); - while (!unixSignal.IsSet) - await Task.Delay(TimeSpan.FromMilliseconds(250), cts.Token); - - logger.LogTrace("{signum} received!", signum); - } - else - logger.LogDebug("{signum} has already been sent", signum); - - signalTcs.TrySetResult(signum); - } - catch (OperationCanceledException) - { - } - } - - var checkerTask = Task.WhenAll( - CheckSignal(Signum.SIGUSR1), - CheckSignal(Signum.SIGUSR2)); - try - { - var signalTask = signalTcs.Task; - - var completedTask = await Task.WhenAny(processTask, signalTask); - if (completedTask == signalTask) - { - var signalReceived = await signalTask; - logger.LogInformation("Received {signalReceived}, forwarding to main TGS process!", signalReceived); - var result = Syscall.kill(childPid, signalReceived); - if (result != 0) - logger.LogWarning( - new UnixIOException(Stdlib.GetLastError()), - "Failed to forward {signalReceived}!", - signalReceived); - } - } - finally - { - cts.Cancel(); - await checkerTask; - } + await processTask; + } + finally + { + cts.Cancel(); + await checkerTask; } } } @@ -252,8 +208,19 @@ async Task CheckSignal(Signum signum) process.WaitForExit(); } } - catch (InvalidOperationException) + catch (InvalidOperationException ex2) + { + logger.LogWarning(ex2, "Error killing host process!"); + } + + try + { + if (File.Exists(updateDirectory)) + File.Delete(updateDirectory); + } + catch (Exception ex2) { + logger.LogWarning(ex2, "Error deleting comms file!"); } logger.LogInformation("Host exited!"); From e37160e7443554dd5e5979962a33f9d33fe8c03b Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:09:29 -0400 Subject: [PATCH 26/34] Fix SystemD heartbeat timings --- .../System/SystemDManager.cs | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index a9a621b7e0b..dd77727e21f 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -177,18 +177,29 @@ void CheckReady() return; } - logger.LogDebug("Starting watchdog loop with interval of {usec}us", watchdogUsec); - var microseconds = UInt64.Parse(watchdogUsec, CultureInfo.InvariantCulture); - var milliseconds = (int)(microseconds / 1000); - if (milliseconds == 0) - milliseconds = 1; + var timeoutIntervalMillis = (int)(microseconds / 1000); + + logger.LogDebug("Starting watchdog loop with interval of {timeoutInterval}ms", timeoutIntervalMillis); + var timeoutInterval = TimeSpan.FromMilliseconds(timeoutIntervalMillis); + var nextExpectedTimeout = DateTimeOffset.UtcNow + timeoutInterval; + var timeToNextExpectedTimeout = nextExpectedTimeout - DateTimeOffset.UtcNow; while (!cancellationToken.IsCancellationRequested) { - await Task.Delay(milliseconds, cancellationToken); + var delayInterval = timeToNextExpectedTimeout / 2; + await Task.Delay(delayInterval, cancellationToken); + + var notifySuccess = SendSDNotify(SDNotifyWatchdog); + + var now = DateTimeOffset.UtcNow; + if (notifySuccess) + nextExpectedTimeout = now + timeoutInterval; + + timeToNextExpectedTimeout = nextExpectedTimeout - now; - SendSDNotify(SDNotifyWatchdog); + if (!notifySuccess) + logger.LogWarning("Missed systemd heartbeat! Expected timeout in {timeoutMs}ms...", timeToNextExpectedTimeout.TotalMilliseconds); } } catch (OperationCanceledException ex) From b75571aa25d4adc6e0c5dc3154ba3b89d024c24e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:15:09 -0400 Subject: [PATCH 27/34] Use SIGTERM for WatchdogSignal The host watchdog will kill the main process if it needs to. --- build/tgstation-server.service | 1 + 1 file changed, 1 insertion(+) diff --git a/build/tgstation-server.service b/build/tgstation-server.service index 5eeff9569a2..1e7dbf87e7e 100644 --- a/build/tgstation-server.service +++ b/build/tgstation-server.service @@ -19,6 +19,7 @@ AmbientCapabilities=CAP_SYS_NICE StandardOutput=null StandardError=null WatchdogSec=60 +WatchdogSignal=SIGTERM [Install] WantedBy=multi-user.target From b7536ae39d5a2f3e6d23f5e13fbfdaf51c66ec06 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:21:41 -0400 Subject: [PATCH 28/34] Fix tgs-configure --- build/package/deb/tgs-configure | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/package/deb/tgs-configure b/build/package/deb/tgs-configure index 5becb6a0362..9103276c793 100755 --- a/build/package/deb/tgs-configure +++ b/build/package/deb/tgs-configure @@ -1,4 +1,5 @@ #!/bin/sh cd /opt/tgstation-server -exec dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll General:SetupWizardMode=Only +export General__SetupWizardMode=Only +exec /usr/bin/dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll From 91f197c121794633a2d4302f995a4b9993fc956e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:22:41 -0400 Subject: [PATCH 29/34] Set WorkingDirectory in .service to avoid tgs.sh --- build/tgstation-server.service | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/tgstation-server.service b/build/tgstation-server.service index 1e7dbf87e7e..837d8fb21fe 100644 --- a/build/tgstation-server.service +++ b/build/tgstation-server.service @@ -9,7 +9,8 @@ After=mssql-server.service [Service] Type=notify-reload NotifyAccess=all -ExecStart=/bin/bash /opt/tgstation-server/tgs.sh General:SetupWizardMode=Never +WorkingDirectory=/opt/tgstation-server +ExecStart=/usr/bin/dotnet Tgstation.Server.Host.Console.dll --General:SetupWizardMode=Never TimeoutStartSec=600 Restart=Always KillMode=process From 95e229d3ce77c33b3f9f3557d2e8620c4e978ab2 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 20:40:48 -0400 Subject: [PATCH 30/34] Fix issues with .deb /etc symlink --- build/package/deb/MakeInstall | 7 +++---- build/package/deb/debian/links | 1 + build/package/deb/debian/postinst | 4 ++++ tgstation-server.sln | 1 + 4 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 build/package/deb/debian/links diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index 5fad7c1b850..083f9c04d16 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -2,7 +2,6 @@ install: build/package/deb/install_artifacts.sh "$(DESTDIR)" - install -D build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" - ln -s "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" "$(DESTDIR)/opt/tgstation-server/appsettings.Production.yml" - install -d "$(DESTDIR)/usr/bin" - install -D build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/" + install -D build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Initial.yml" + install src/Tgstation.Server.Host/appsettings.yml "$(DESTDIR)/etc/tgstation-server/appsettings.ex.yml" + install -D build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/tgs-configure" diff --git a/build/package/deb/debian/links b/build/package/deb/debian/links new file mode 100644 index 00000000000..8a960e0a76f --- /dev/null +++ b/build/package/deb/debian/links @@ -0,0 +1 @@ +/etc/tgstation-server/appsettings.Production.yml /opt/tgstation-server/appsettings.Production.yml diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index 59b7e749960..f6fa53b4a84 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,6 +1,10 @@ #!/bin/sh -e if [ "$1" = "configure" ]; then + # Copy appsettings.Initial.yml to .Production to make the symlink work + cp /etc/tgstation-server/appsettings.Initial.yml /etc/tgstation-server/appsettings.Production.yml + chown 600 /etc/tgstation-server/appsettings.Production.yml + # disable first time startup so user can configure deb-systemd-helper mask 'tgstation-server.service' >/dev/null || true fi diff --git a/tgstation-server.sln b/tgstation-server.sln index fb73c96e355..8c700d5f296 100644 --- a/tgstation-server.sln +++ b/tgstation-server.sln @@ -216,6 +216,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "debian", "debian", "{08E7C6 build\package\deb\debian\changelog = build\package\deb\debian\changelog build\package\deb\debian\control = build\package\deb\debian\control build\package\deb\debian\copyright = build\package\deb\debian\copyright + build\package\deb\debian\links = build\package\deb\debian\links build\package\deb\debian\postinst = build\package\deb\debian\postinst build\package\deb\debian\prerm = build\package\deb\debian\prerm build\package\deb\debian\rules = build\package\deb\debian\rules From dd60436c27499787378dae8068fbc2274c69142c Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 21:47:14 -0400 Subject: [PATCH 31/34] Let the systemd service fail on default startup --- build/package/deb/debian/postinst | 6 ++---- src/Tgstation.Server.Host/appsettings.yml | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index f6fa53b4a84..e58541d77ba 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -4,14 +4,13 @@ if [ "$1" = "configure" ]; then # Copy appsettings.Initial.yml to .Production to make the symlink work cp /etc/tgstation-server/appsettings.Initial.yml /etc/tgstation-server/appsettings.Production.yml chown 600 /etc/tgstation-server/appsettings.Production.yml - - # disable first time startup so user can configure - deb-systemd-helper mask 'tgstation-server.service' >/dev/null || true fi #DEBHELPER# if [ "$1" = "configure" ]; then + deb-systemd-helper stop 'tgstation-server.service' >/dev/null || true + echo " _ _ _ _ " echo " | |_ __ _ ___| |_ __ _| |_(_) ___ _ __ ___ ___ _ ____ _____ _ __ " echo " | __/ _\` / __| __/ _\` | __| |/ _ \\| '_ \\ _____/ __|/ _ \\ '__\\ \\ / / _ \\ '__|" @@ -22,5 +21,4 @@ if [ "$1" = "configure" ]; then echo "Run 'sudo tgs-configure' to interactively configure your server" echo "Alternatively, edit '/etc/tgstation-server/appsettings.Production.yml' to your desired specifications" echo "Once complete, run 'sudo systemctl start tgstation-server' to start the service" - echo "You should do this now to prevent the service from starting with invalid configuration on the next system reboot" fi diff --git a/src/Tgstation.Server.Host/appsettings.yml b/src/Tgstation.Server.Host/appsettings.yml index 273bebda9d6..10af3e04e78 100644 --- a/src/Tgstation.Server.Host/appsettings.yml +++ b/src/Tgstation.Server.Host/appsettings.yml @@ -19,7 +19,7 @@ Session: LowPriorityDeploymentProcesses: true # If TGS Deployments should run as lower priority processes FileLogging: Directory: # Directory in which log files are stored. Windows default: %PROGRAMDATA%/tgstation-server. Linux default: /var/log/tgstation-server - Disable: false # Disable file logging entirely + Disable: true # Disable file logging entirely LogLevel: Debug # Level of file logging verbosity. Can be one of Trace, Debug, Information, Warning, Error, or Critical MicrosoftLogLevel: Warning # Level of file logging verbosity from Microsoft dependecies (i.e. webserver, database object relational mapper, etc...). Can be one of Trace, Debug, Information, Warning, Error, or Critical Logging: From 10f2852c6adfacd78fcd2cf7b4d8219df5391621 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 21:57:25 -0400 Subject: [PATCH 32/34] Debian is smart about /etc files. Fix ownership --- build/package/deb/MakeInstall | 2 +- build/package/deb/debian/postinst | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/build/package/deb/MakeInstall b/build/package/deb/MakeInstall index 083f9c04d16..ac109ab592e 100755 --- a/build/package/deb/MakeInstall +++ b/build/package/deb/MakeInstall @@ -2,6 +2,6 @@ install: build/package/deb/install_artifacts.sh "$(DESTDIR)" - install -D build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Initial.yml" + install -D build/package/deb/appsettings.Initial.yml "$(DESTDIR)/etc/tgstation-server/appsettings.Production.yml" install src/Tgstation.Server.Host/appsettings.yml "$(DESTDIR)/etc/tgstation-server/appsettings.ex.yml" install -D build/package/deb/tgs-configure "$(DESTDIR)/usr/bin/tgs-configure" diff --git a/build/package/deb/debian/postinst b/build/package/deb/debian/postinst index e58541d77ba..9f71a1931f2 100755 --- a/build/package/deb/debian/postinst +++ b/build/package/deb/debian/postinst @@ -1,14 +1,9 @@ #!/bin/sh -e -if [ "$1" = "configure" ]; then - # Copy appsettings.Initial.yml to .Production to make the symlink work - cp /etc/tgstation-server/appsettings.Initial.yml /etc/tgstation-server/appsettings.Production.yml - chown 600 /etc/tgstation-server/appsettings.Production.yml -fi - #DEBHELPER# if [ "$1" = "configure" ]; then + chmod 600 /etc/tgstation-server deb-systemd-helper stop 'tgstation-server.service' >/dev/null || true echo " _ _ _ _ " From 259eb8b2b3d496efbcdd98e814a32b34566e243d Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 23:11:15 -0400 Subject: [PATCH 33/34] Fix Live tests having no file logs --- tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs index 66e0d46e90b..2b664ce904b 100644 --- a/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs +++ b/tests/Tgstation.Server.Tests/Live/LiveTestingServer.cs @@ -109,6 +109,7 @@ public LiveTestingServer(SwarmConfiguration swarmConfiguration, bool enableOAuth String.Format(CultureInfo.InvariantCulture, "General:HostApiDocumentation={0}", DumpOpenApiSpecpath), String.Format(CultureInfo.InvariantCulture, "FileLogging:Directory={0}", Path.Combine(Directory, "Logs")), String.Format(CultureInfo.InvariantCulture, "FileLogging:LogLevel={0}", "Trace"), + String.Format(CultureInfo.InvariantCulture, "FileLogging:Disable={0}", false), String.Format(CultureInfo.InvariantCulture, "General:ValidInstancePaths:0={0}", Directory), "General:ByondTopicTimeout=3000", $"Session:HighPriorityLiveDreamDaemon={HighPriorityDreamDaemon}", From 2102a833329658499d4c1490f3ccb14b52fdcb36 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Fri, 23 Jun 2023 23:27:06 -0400 Subject: [PATCH 34/34] Guard against PInvoke exceptions calling sd_notify --- src/Tgstation.Server.Host/System/SystemDManager.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Tgstation.Server.Host/System/SystemDManager.cs b/src/Tgstation.Server.Host/System/SystemDManager.cs index dd77727e21f..99f4ade686d 100644 --- a/src/Tgstation.Server.Host/System/SystemDManager.cs +++ b/src/Tgstation.Server.Host/System/SystemDManager.cs @@ -222,7 +222,17 @@ void CheckReady() bool SendSDNotify(string command) { logger.LogTrace("Sending sd_notify {message}...", command); - var result = NativeMethods.sd_notify(0, command); + int result; + try + { + result = NativeMethods.sd_notify(0, command); + } + catch (Exception ex) + { + logger.LogInformation(ex, "Exception attempting to invoke sd_notify!"); + return false; + } + if (result > 0) return true;