Merge pull request #1570 from tgstation/MoreDebGotchas

Removes Configuration auto-reloading. Make deployment event script respect low priority config.
This commit is contained in:
Jordan Dominion
2023-06-23 02:39:04 -04:00
committed by GitHub
29 changed files with 480 additions and 124 deletions
+7 -1
View File
@@ -419,9 +419,15 @@ If TGS was installed via a package manager, using the TGS self updater will caus
To avoid this, use the package manager to update TGS. It is just as seamless as the self-updater.
##### apt
```sh
sudo apt update && sudo apt upgrade -y
```
#### Notifications
If a server update is available, it will be indicated in the response from the GET /Administration endpoint. For more active notifications, you can subscribe to [this GitHub discussion](https://github.com/tgstation/tgstation-server/discussions/1322).
If a server update is available, it will be indicated in the response from the GET /Administration endpoint and shown as a green exclamation mark in the webpanel navbar. For more active notifications, you can subscribe to [this GitHub discussion](https://github.com/tgstation/tgstation-server/discussions/1322).
### Users
+7 -1
View File
@@ -1,8 +1,14 @@
#!/usr/bin/make -f
install:
mkdir -p $(DESTDIR)/opt/tgstation-server
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
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
+1
View File
@@ -21,6 +21,7 @@ Depends:
libstdc++6:i386 [amd64],
libstdc++6 [i386],
gcc-multilib [amd64],
libsystemd0,
Recommends:
gdb,
Description: A production scale tool for BYOND server management
+18 -4
View File
@@ -1,7 +1,21 @@
#!/bin/bash
#!/bin/sh -e
pushd /opt/tgstation-server
dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll General:SetupWizardMode=Only
popd
if [[ "$1" = "configure" ]]; then
systemctl mask tgstation-server
fi
#DEBHELPER#
if [[ "$1" = "configure" ]]; then
echo " _ _ _ _ "
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"
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
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#!/bin/sh -e
#DEBHELPER#
+1 -1
View File
@@ -25,4 +25,4 @@ override_dh_strip:
override_dh_shlibdeps:
override_dh_installsystemd:
dh_installsystemd -v --name=tgstation-server --restart-after-upgrade
dh_installsystemd -v --restart-after-upgrade
+5
View File
@@ -0,0 +1,5 @@
#!/bin/sh
pushd /opt/tgstation-server
dotnet /opt/tgstation-server/lib/Default/Tgstation.Server.Host.dll General:SetupWizardMode=Only
popd
-1
View File
@@ -14,7 +14,6 @@ if [ ! -f $PROD_CONFIG ]; then
fi
echo "$PROD_CONFIG not detected! Creating empty and running setup wizard..."
# Important, config reloading doesn't work with symlinks
echo "{}" > $PROD_CONFIG
fi
+4
View File
@@ -7,13 +7,17 @@ After=postgresql.service
After=mssql-server.service
[Service]
Type=notify
NotifyAccess=all
ExecStart=/bin/bash /opt/tgstation-server/tgs.sh General:SetupWizardMode=Never
TimeoutStartSec=600
Restart=Always
KillMode=process
RestartKillSignal=SIGUSR2
AmbientCapabilities=CAP_SYS_NICE
StandardOutput=null
StandardError=null
WatchdogSec=60
[Install]
WantedBy=multi-user.target
@@ -165,6 +165,7 @@ namespace Tgstation.Server.Host.Components.Byond
ActiveVersion?.ToString(),
stringVersion,
},
false,
cancellationToken);
ActiveVersion = version;
@@ -475,7 +476,7 @@ namespace Tgstation.Server.Host.Components.Byond
progressReporter.StageName = "Running event";
var versionString = version.ToString();
await eventConsumer.HandleEvent(EventType.ByondInstallStart, new List<string> { versionString }, cancellationToken);
await eventConsumer.HandleEvent(EventType.ByondInstallStart, new List<string> { versionString }, false, cancellationToken);
await InstallVersionFiles(progressReporter, version, customVersionStream, cancellationToken);
@@ -484,7 +485,7 @@ namespace Tgstation.Server.Host.Components.Byond
catch (Exception ex)
{
if (ex is not OperationCanceledException)
await eventConsumer.HandleEvent(EventType.ByondInstallFail, new List<string> { ex.Message }, cancellationToken);
await eventConsumer.HandleEvent(EventType.ByondInstallFail, new List<string> { ex.Message }, false, cancellationToken);
lock (installedVersions)
installedVersions.Remove(version);
@@ -448,7 +448,7 @@ namespace Tgstation.Server.Host.Components.Deployment
async Task DeleteCompileJobContent(string directory, CancellationToken cancellationToken)
{
// Then call the cleanup event, waiting here first
await eventConsumer.HandleEvent(EventType.DeploymentCleanup, new List<string> { ioManager.ResolvePath(directory) }, cancellationToken);
await eventConsumer.HandleEvent(EventType.DeploymentCleanup, new List<string> { ioManager.ResolvePath(directory) }, true, cancellationToken);
await ioManager.DeleteDirectory(directory, cancellationToken);
}
}
@@ -386,7 +386,7 @@ namespace Tgstation.Server.Host.Components.Deployment
repoName,
cancellationToken);
var eventTask = eventConsumer.HandleEvent(EventType.DeploymentComplete, Enumerable.Empty<string>(), cancellationToken);
var eventTask = eventConsumer.HandleEvent(EventType.DeploymentComplete, Enumerable.Empty<string>(), false, cancellationToken);
try
{
@@ -537,7 +537,7 @@ namespace Tgstation.Server.Host.Components.Deployment
{
// DCT: Cancellation token is for job, delaying here is fine
progressReporter.StageName = "Running CompileCancelled event";
await eventConsumer.HandleEvent(EventType.CompileCancelled, Enumerable.Empty<string>(), CancellationToken.None);
await eventConsumer.HandleEvent(EventType.CompileCancelled, Enumerable.Empty<string>(), true, CancellationToken.None);
throw;
}
finally
@@ -594,6 +594,7 @@ namespace Tgstation.Server.Host.Components.Deployment
repoOrigin.ToString(),
$"{byondLock.Version.Major}.{byondLock.Version.Minor}",
},
true,
cancellationToken);
// determine the dme
@@ -632,6 +633,7 @@ namespace Tgstation.Server.Host.Components.Deployment
repoOrigin.ToString(),
$"{byondLock.Version.Major}.{byondLock.Version.Minor}",
},
true,
cancellationToken);
// run compiler
@@ -672,6 +674,7 @@ namespace Tgstation.Server.Host.Components.Deployment
exitCode == 0 ? "1" : "0",
byondVersion.ToString(),
},
true,
cancellationToken);
throw;
}
@@ -684,6 +687,7 @@ namespace Tgstation.Server.Host.Components.Deployment
resolvedOutputDirectory,
byondVersion.ToString(),
},
true,
cancellationToken);
logger.LogTrace("Applying static game file symlinks...");
@@ -957,7 +961,7 @@ namespace Tgstation.Server.Host.Components.Deployment
try
{
// DCT: None available
await eventConsumer.HandleEvent(EventType.DeploymentCleanup, new List<string> { jobPath }, CancellationToken.None);
await eventConsumer.HandleEvent(EventType.DeploymentCleanup, new List<string> { jobPath }, true, CancellationToken.None);
await ioManager.DeleteDirectory(jobPath, CancellationToken.None);
}
catch (Exception e)
@@ -31,15 +31,15 @@ namespace Tgstation.Server.Host.Components.Events
}
/// <inheritdoc />
public async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, CancellationToken cancellationToken)
public async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(parameters);
if (watchdog == null)
throw new InvalidOperationException("EventConsumer used without watchdog set!");
var scriptTask = configuration.HandleEvent(eventType, parameters, cancellationToken);
await watchdog.HandleEvent(eventType, parameters, cancellationToken);
var scriptTask = configuration.HandleEvent(eventType, parameters, deploymentPipeline, cancellationToken);
await watchdog.HandleEvent(eventType, parameters, deploymentPipeline, cancellationToken);
await scriptTask;
}
@@ -49,11 +49,10 @@ namespace Tgstation.Server.Host.Components.Events
/// <param name="watchdog">The value of <see cref="watchdog"/>.</param>
public void SetWatchdog(IWatchdog watchdog)
{
#pragma warning disable IDE0016 // Use 'throw' expression
ArgumentNullException.ThrowIfNull(watchdog);
#pragma warning restore IDE0016 // Use 'throw' expression
if (this.watchdog != null)
throw new InvalidOperationException("watchdog already set!");
this.watchdog = watchdog;
}
}
@@ -14,8 +14,9 @@ namespace Tgstation.Server.Host.Components.Events
/// </summary>
/// <param name="eventType">The <see cref="EventType"/>.</param>
/// <param name="parameters">An <see cref="IEnumerable{T}"/> of <see cref="string"/> parameters for <paramref name="eventType"/>.</param>
/// <param name="deploymentPipeline">If this event is part of the deployment pipeline.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task HandleEvent(EventType eventType, IEnumerable<string> parameters, CancellationToken cancellationToken);
Task HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken);
}
}
@@ -306,9 +306,10 @@ namespace Tgstation.Server.Host.Components
// the main point of auto update is to pull the remote
await repo.FetchOrigin(
NextProgressReporter("Fetch Origin"),
repositorySettings.AccessUser,
repositorySettings.AccessToken,
NextProgressReporter("Fetch Origin"),
true,
cancellationToken);
var hasDbChanges = false;
@@ -380,9 +381,10 @@ namespace Tgstation.Server.Host.Components
await UpdateRevInfo(repo.Head, false, null);
var result = await repo.MergeOrigin(
NextProgressReporter("Merge Origin"),
repositorySettings.CommitterName,
repositorySettings.CommitterEmail,
NextProgressReporter("Merge Origin"),
true,
cancellationToken);
var preserveTestMerges = repositorySettings.AutoUpdatesKeepTestMerges.Value;
@@ -428,10 +430,11 @@ namespace Tgstation.Server.Host.Components
const string StageName = "Resetting to origin...";
logger.LogTrace(StageName);
await repo.ResetToOrigin(
NextProgressReporter(StageName),
repositorySettings.AccessUser,
repositorySettings.AccessToken,
repositorySettings.UpdateSubmodules.Value,
NextProgressReporter(StageName),
true,
cancellationToken);
var currentHead = repo.Head;
@@ -451,12 +454,13 @@ namespace Tgstation.Server.Host.Components
if (repositorySettings.AutoUpdatesSynchronize.Value && startSha != repo.Head && (shouldSyncTracked || repositorySettings.PushTestMergeCommits.Value))
{
var pushedOrigin = await repo.Sychronize(
NextProgressReporter("Synchronize"),
repositorySettings.AccessUser,
repositorySettings.AccessToken,
repositorySettings.CommitterName,
repositorySettings.CommitterEmail,
NextProgressReporter("Synchronize"),
shouldSyncTracked,
true,
cancellationToken);
var currentHead = repo.Head;
if (currentHead != currentRevInfo.CommitSha)
@@ -492,7 +496,7 @@ namespace Tgstation.Server.Host.Components
{
await asyncDelayer.Delay(TimeSpan.FromMinutes(minutes > Int32.MaxValue ? Int32.MaxValue : minutes), cancellationToken);
logger.LogInformation("Beginning auto update...");
await eventConsumer.HandleEvent(EventType.InstanceAutoUpdateStart, Enumerable.Empty<string>(), cancellationToken);
await eventConsumer.HandleEvent(EventType.InstanceAutoUpdateStart, Enumerable.Empty<string>(), true, cancellationToken);
try
{
var repositoryUpdateJob = new Job
@@ -281,7 +281,8 @@ namespace Tgstation.Server.Host.Components
platformIdentifier,
fileTransferService,
loggerFactory.CreateLogger<StaticFiles.Configuration>(),
generalConfiguration);
generalConfiguration,
sessionConfiguration);
var eventConsumer = new EventConsumer(configuration);
var repoManager = new RepositoryManager(
repositoryFactory,
@@ -83,31 +83,35 @@ namespace Tgstation.Server.Host.Components.Repository
/// <summary>
/// Fetch commits from the origin repository.
/// </summary>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="username">The username to fetch from the origin repository.</param>
/// <param name="password">The password to fetch from the origin repository.</param>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="deploymentPipeline">If any events created should be marked as part of the deployment pipeline.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
Task FetchOrigin(
JobProgressReporter progressReporter,
string username,
string password,
JobProgressReporter progressReporter,
bool deploymentPipeline,
CancellationToken cancellationToken);
/// <summary>
/// Requires the current HEAD to be a tracked reference. Hard resets the reference to what it tracks on the origin repository.
/// </summary>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="username">The username used for fetching from submodule repositories.</param>
/// <param name="password">The password used for fetching from submodule repositories.</param>
/// <param name="updateSubmodules">If a submodule update should be attempted after the merge.</param>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="deploymentPipeline">If any events created should be marked as part of the deployment pipeline.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in the SHA of the new HEAD.</returns>
Task ResetToOrigin(
JobProgressReporter progressReporter,
string username,
string password,
bool updateSubmodules,
JobProgressReporter progressReporter,
bool deploymentPipeline,
CancellationToken cancellationToken);
/// <summary>
@@ -122,31 +126,39 @@ namespace Tgstation.Server.Host.Components.Repository
/// <summary>
/// Requires the current HEAD to be a tracked reference. Merges the reference to what it tracks on the origin repository.
/// </summary>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="committerName">The name of the merge committer.</param>
/// <param name="committerEmail">The e-mail of the merge committer.</param>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="deploymentPipeline">If any events created should be marked as part of the deployment pipeline.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in a <see cref="Nullable{T}"/> <see cref="bool"/> representing the merge result that is <see langword="true"/> after a fast forward, <see langword="false"/> on a merge or up to date, <see langword="null"/> on a conflict.</returns>
Task<bool?> MergeOrigin(string committerName, string committerEmail, JobProgressReporter progressReporter, CancellationToken cancellationToken);
Task<bool?> MergeOrigin(
JobProgressReporter progressReporter,
string committerName,
string committerEmail,
bool deploymentPipeline,
CancellationToken cancellationToken);
/// <summary>
/// Runs the synchronize event script and attempts to push any changes made to the <see cref="IRepository"/> if on a tracked branch.
/// </summary>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="username">The username to fetch from the origin repository.</param>
/// <param name="password">The password to fetch from the origin repository.</param>
/// <param name="committerName">The name of the potential committer.</param>
/// <param name="committerEmail">The e-mail of the potential committer.</param>
/// <param name="progressReporter">The <see cref="JobProgressReporter"/> to report progress of the operation.</param>
/// <param name="synchronizeTrackedBranch">If the synchronizations should be made to the tracked reference as opposed to a temporary branch.</param>
/// <param name="deploymentPipeline">If any events created should be marked as part of the deployment pipeline.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task{TResult}"/> resulting in <see langword="true"/> if commits were pushed to the tracked origin reference, <see langword="false"/> otherwise.</returns>
Task<bool> Sychronize(
JobProgressReporter progressReporter,
string username,
string password,
string committerName,
string committerEmail,
JobProgressReporter progressReporter,
bool synchronizeTrackedBranch,
bool deploymentPipeline,
CancellationToken cancellationToken);
/// <summary>
@@ -333,6 +333,7 @@ namespace Tgstation.Server.Host.Components.Repository
await eventConsumer.HandleEvent(
EventType.RepoMergeConflict,
arguments,
false,
cancellationToken);
return new TestMergeResult
{
@@ -359,6 +360,7 @@ namespace Tgstation.Server.Host.Components.Repository
progressReporter.CreateSection("Update Submodules", progressFactor),
username,
password,
false,
cancellationToken);
}
}
@@ -371,6 +373,7 @@ namespace Tgstation.Server.Host.Components.Repository
testMergeParameters.TargetCommitSha,
testMergeParameters.Comment,
},
false,
cancellationToken);
return new TestMergeResult
@@ -392,7 +395,7 @@ namespace Tgstation.Server.Host.Components.Repository
ArgumentNullException.ThrowIfNull(committish);
ArgumentNullException.ThrowIfNull(progressReporter);
logger.LogDebug("Checkout object: {committish}...", committish);
await eventConsumer.HandleEvent(EventType.RepoCheckout, new List<string> { committish }, cancellationToken);
await eventConsumer.HandleEvent(EventType.RepoCheckout, new List<string> { committish }, false, cancellationToken);
await Task.Factory.StartNew(
() =>
{
@@ -411,15 +414,21 @@ namespace Tgstation.Server.Host.Components.Repository
progressReporter.CreateSection(null, 1.0 / 3),
username,
password,
false,
cancellationToken);
}
/// <inheritdoc />
public async Task FetchOrigin(string username, string password, JobProgressReporter progressReporter, CancellationToken cancellationToken)
public async Task FetchOrigin(
JobProgressReporter progressReporter,
string username,
string password,
bool deploymentPipeline,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(progressReporter);
logger.LogDebug("Fetch origin...");
await eventConsumer.HandleEvent(EventType.RepoFetch, Enumerable.Empty<string>(), cancellationToken);
await eventConsumer.HandleEvent(EventType.RepoFetch, Enumerable.Empty<string>(), deploymentPipeline, cancellationToken);
await Task.Factory.StartNew(
() =>
{
@@ -458,10 +467,11 @@ namespace Tgstation.Server.Host.Components.Repository
/// <inheritdoc />
public async Task ResetToOrigin(
JobProgressReporter progressReporter,
string username,
string password,
bool updateSubmodules,
JobProgressReporter progressReporter,
bool deploymentPipeline,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(progressReporter);
@@ -469,7 +479,7 @@ namespace Tgstation.Server.Host.Components.Repository
throw new JobException(ErrorCode.RepoReferenceRequired);
logger.LogTrace("Reset to origin...");
var trackedBranch = libGitRepo.Head.TrackedBranch;
await eventConsumer.HandleEvent(EventType.RepoResetOrigin, new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, cancellationToken);
await eventConsumer.HandleEvent(EventType.RepoResetOrigin, new List<string> { trackedBranch.FriendlyName, trackedBranch.Tip.Sha }, deploymentPipeline, cancellationToken);
await ResetToSha(
trackedBranch.Tip.Sha,
progressReporter.CreateSection(null, updateSubmodules ? 2.0 / 3 : 1.0),
@@ -480,6 +490,7 @@ namespace Tgstation.Server.Host.Components.Repository
progressReporter.CreateSection(null, 1.0 / 3),
username,
password,
deploymentPipeline,
cancellationToken);
}
@@ -547,9 +558,10 @@ namespace Tgstation.Server.Host.Components.Repository
/// <inheritdoc />
public async Task<bool?> MergeOrigin(
JobProgressReporter progressReporter,
string committerName,
string committerEmail,
JobProgressReporter progressReporter,
bool deploymentPipeline,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(progressReporter);
@@ -606,7 +618,17 @@ namespace Tgstation.Server.Host.Components.Repository
if (result.Status == MergeStatus.Conflicts)
{
await eventConsumer.HandleEvent(EventType.RepoMergeConflict, new List<string> { oldTip.Sha, trackedBranch.Tip.Sha, oldHead.FriendlyName ?? UnknownReference, trackedBranch.FriendlyName }, cancellationToken);
await eventConsumer.HandleEvent(
EventType.RepoMergeConflict,
new List<string>
{
oldTip.Sha,
trackedBranch.Tip.Sha,
oldHead.FriendlyName ?? UnknownReference,
trackedBranch.FriendlyName,
},
deploymentPipeline,
cancellationToken);
return null;
}
@@ -615,12 +637,13 @@ namespace Tgstation.Server.Host.Components.Repository
/// <inheritdoc />
public async Task<bool> Sychronize(
JobProgressReporter progressReporter,
string username,
string password,
string committerName,
string committerEmail,
JobProgressReporter progressReporter,
bool synchronizeTrackedBranch,
bool deploymentPipeline,
CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(committerName);
@@ -661,6 +684,7 @@ namespace Tgstation.Server.Host.Components.Repository
{
ioMananger.ResolvePath(),
},
deploymentPipeline,
cancellationToken);
}
finally
@@ -964,9 +988,15 @@ namespace Tgstation.Server.Host.Components.Repository
/// <param name="progressReporter"><see cref="JobProgressReporter"/> of the operation.</param>
/// <param name="username">The username for the <see cref="credentialsProvider"/>.</param>
/// <param name="password">The password for the <see cref="credentialsProvider"/>.</param>
/// <param name="deploymentPipeline">If any events created should be marked as part of the deployment pipeline.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
async Task UpdateSubmodules(JobProgressReporter progressReporter, string username, string password, CancellationToken cancellationToken)
async Task UpdateSubmodules(
JobProgressReporter progressReporter,
string username,
string password,
bool deploymentPipeline,
CancellationToken cancellationToken)
{
var submoduleCount = libGitRepo.Submodules.Count();
if (submoduleCount == 0)
@@ -1032,7 +1062,11 @@ namespace Tgstation.Server.Host.Components.Repository
}
}
await eventConsumer.HandleEvent(EventType.RepoSubmoduleUpdate, new List<string> { submodule.Name }, cancellationToken);
await eventConsumer.HandleEvent(
EventType.RepoSubmoduleUpdate,
new List<string> { submodule.Name },
deploymentPipeline,
cancellationToken);
}
}
@@ -152,11 +152,10 @@ namespace Tgstation.Server.Host.Components.Repository
CancellationToken cancellationToken)
#pragma warning restore CA1502, CA1506
{
var repoManager = instance.RepositoryManager;
using var repo = await repoManager.LoadRepository(cancellationToken);
if (repo == null)
throw new JobException(ErrorCode.RepoMissing);
_ = job; // shuts up an IDE warning
var repoManager = instance.RepositoryManager;
using var repo = await repoManager.LoadRepository(cancellationToken) ?? throw new JobException(ErrorCode.RepoMissing);
var modelHasShaOrReference = model.CheckoutSha != null || model.Reference != null;
var startReference = repo.Reference;
@@ -252,11 +251,21 @@ namespace Tgstation.Server.Host.Components.Repository
{
if (!repo.Tracking)
throw new JobException(ErrorCode.RepoReferenceRequired);
await repo.FetchOrigin(currentModel.AccessUser, currentModel.AccessToken, NextProgressReporter("Fetch Origin"), cancellationToken);
await repo.FetchOrigin(
NextProgressReporter("Fetch Origin"),
currentModel.AccessUser,
currentModel.AccessToken,
false,
cancellationToken);
if (!modelHasShaOrReference)
{
var fastForward = await repo.MergeOrigin(committerName, currentModel.CommitterEmail, NextProgressReporter("Merge Origin"), cancellationToken);
var fastForward = await repo.MergeOrigin(
NextProgressReporter("Merge Origin"),
committerName,
currentModel.CommitterEmail,
false,
cancellationToken);
if (!fastForward.HasValue)
throw new JobException(ErrorCode.RepoMergeConflict);
lastRevisionInfo.OriginCommitSha = await repo.GetOriginSha(cancellationToken);
@@ -264,12 +273,13 @@ namespace Tgstation.Server.Host.Components.Repository
if (fastForward.Value)
{
await repo.Sychronize(
NextProgressReporter("Sychronize"),
currentModel.AccessUser,
currentModel.AccessToken,
currentModel.CommitterName,
currentModel.CommitterEmail,
NextProgressReporter("Sychronize"),
true,
false,
cancellationToken);
postUpdateSha = repo.Head;
}
@@ -315,18 +325,20 @@ namespace Tgstation.Server.Host.Components.Repository
if (!repo.Tracking)
throw new JobException(ErrorCode.RepoReferenceNotTracking);
await repo.ResetToOrigin(
NextProgressReporter("Reset to Origin"),
currentModel.AccessUser,
currentModel.AccessToken,
updateSubmodules,
NextProgressReporter("Reset to Origin"),
false,
cancellationToken);
await repo.Sychronize(
NextProgressReporter("Synchronize"),
currentModel.AccessUser,
currentModel.AccessToken,
currentModel.CommitterName,
currentModel.CommitterEmail,
NextProgressReporter("Synchronize"),
true,
false,
cancellationToken);
await CallLoadRevInfo();
@@ -473,7 +485,7 @@ namespace Tgstation.Server.Host.Components.Repository
if (revInfoWereLookingFor != null)
{
// goteem
logger.LogDebug("Reusing existing SHA {0}...", revInfoWereLookingFor.CommitSha);
logger.LogDebug("Reusing existing SHA {sha}...", revInfoWereLookingFor.CommitSha);
await repo.ResetToSha(revInfoWereLookingFor.CommitSha, NextProgressReporter($"Reset to {revInfoWereLookingFor.CommitSha[..7]}"), cancellationToken);
lastRevisionInfo = revInfoWereLookingFor;
}
@@ -535,11 +547,12 @@ namespace Tgstation.Server.Host.Components.Repository
if (currentModel.PushTestMergeCommits.Value && (startSha != currentHead || (postUpdateSha != null && postUpdateSha != currentHead)))
{
await repo.Sychronize(
NextProgressReporter("Synchronize"),
currentModel.AccessUser,
currentModel.AccessToken,
currentModel.CommitterName,
currentModel.CommitterEmail,
NextProgressReporter("Synchronize"),
false,
false,
cancellationToken);
await UpdateRevInfo();
@@ -549,6 +549,7 @@ namespace Tgstation.Server.Host.Components.Session
{
process.Id.ToString(CultureInfo.InvariantCulture),
},
false,
cancellationToken);
return process;
@@ -128,6 +128,11 @@ namespace Tgstation.Server.Host.Components.StaticFiles
/// </summary>
readonly GeneralConfiguration generalConfiguration;
/// <summary>
/// The <see cref="SessionConfiguration"/> for <see cref="Configuration"/>.
/// </summary>
readonly SessionConfiguration sessionConfiguration;
/// <summary>
/// The <see cref="SemaphoreSlim"/> for <see cref="Configuration"/>. Also used as a <see langword="lock"/> <see cref="object"/>.
/// </summary>
@@ -155,6 +160,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
/// <param name="fileTransferService">The value of <see cref="fileTransferService"/>.</param>
/// <param name="logger">The value of <see cref="logger"/>.</param>
/// <param name="generalConfiguration">The value of <see cref="generalConfiguration"/>.</param>
/// <param name="sessionConfiguration">The value of <see cref="sessionConfiguration"/>.</param>
public Configuration(
IIOManager ioManager,
ISynchronousIOManager synchronousIOManager,
@@ -164,7 +170,8 @@ namespace Tgstation.Server.Host.Components.StaticFiles
IPlatformIdentifier platformIdentifier,
IFileTransferTicketProvider fileTransferService,
ILogger<Configuration> logger,
GeneralConfiguration generalConfiguration)
GeneralConfiguration generalConfiguration,
SessionConfiguration sessionConfiguration)
{
this.ioManager = ioManager ?? throw new ArgumentNullException(nameof(ioManager));
this.synchronousIOManager = synchronousIOManager ?? throw new ArgumentNullException(nameof(synchronousIOManager));
@@ -175,6 +182,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
this.fileTransferService = fileTransferService ?? throw new ArgumentNullException(nameof(fileTransferService));
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
this.generalConfiguration = generalConfiguration ?? throw new ArgumentNullException(nameof(generalConfiguration));
this.sessionConfiguration = sessionConfiguration ?? throw new ArgumentNullException(nameof(sessionConfiguration));
semaphore = new SemaphoreSlim(1);
disposeCts = new CancellationTokenSource();
@@ -592,7 +600,7 @@ namespace Tgstation.Server.Host.Components.StaticFiles
public Task StopAsync(CancellationToken cancellationToken) => EnsureDirectories(cancellationToken);
/// <inheritdoc />
public async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, CancellationToken cancellationToken)
public async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(parameters);
@@ -639,6 +647,9 @@ namespace Tgstation.Server.Host.Components.StaticFiles
noShellExecute: true))
using (cancellationToken.Register(() => script.Terminate()))
{
if (sessionConfiguration.LowPriorityDeploymentProcesses)
script.AdjustPriority(false);
var exitCode = await script.Lifetime;
cancellationToken.ThrowIfCancellationRequested();
var scriptOutput = await script.GetCombinedOutput(cancellationToken);
@@ -112,7 +112,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
var eventType = Server.TerminationWasRequested
? EventType.WorldEndProcess
: EventType.WatchdogCrash;
await HandleEvent(eventType, Enumerable.Empty<string>(), false, cancellationToken);
await HandleEventImpl(eventType, Enumerable.Empty<string>(), false, cancellationToken);
var exitWord = Server.TerminationWasRequested ? "exited" : "crashed";
if (Server.RebootState == Session.RebootState.Shutdown)
@@ -143,7 +143,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
gracefulRebootRequired = false;
Server.ResetRebootState();
var eventTask = HandleEvent(EventType.WorldReboot, Enumerable.Empty<string>(), false, cancellationToken);
var eventTask = HandleEventImpl(EventType.WorldReboot, Enumerable.Empty<string>(), false, cancellationToken);
try
{
switch (rebootState)
@@ -174,7 +174,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
await HandleNewDmbAvailable(cancellationToken);
break;
case MonitorActivationReason.ActiveServerPrimed:
await HandleEvent(EventType.WorldPrime, Enumerable.Empty<string>(), false, cancellationToken);
await HandleEventImpl(EventType.WorldPrime, Enumerable.Empty<string>(), false, cancellationToken);
break;
case MonitorActivationReason.ActiveServerStartup:
break; // unused in BasicWatchdog
@@ -449,7 +449,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
}
/// <inheritdoc />
async Task IEventConsumer.HandleEvent(EventType eventType, IEnumerable<string> parameters, CancellationToken cancellationToken)
async Task IEventConsumer.HandleEvent(EventType eventType, IEnumerable<string> parameters, bool deploymentPipeline, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(parameters);
@@ -509,7 +509,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
? "Launching..."
: "Reattaching..."); // simple announce
if (reattachInfo == null)
eventTask = HandleEvent(EventType.WatchdogLaunch, Enumerable.Empty<string>(), false, cancellationToken);
eventTask = HandleEventImpl(EventType.WatchdogLaunch, Enumerable.Empty<string>(), false, cancellationToken);
}
// since neither server is running, this is safe to do
@@ -693,13 +693,13 @@ namespace Tgstation.Server.Host.Components.Watchdog
/// <param name="relayToSession">If the event should be sent to DreamDaemon.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
protected async Task HandleEvent(EventType eventType, IEnumerable<string> parameters, bool relayToSession, CancellationToken cancellationToken)
protected async Task HandleEventImpl(EventType eventType, IEnumerable<string> parameters, bool relayToSession, CancellationToken cancellationToken)
{
try
{
var sessionEventTask = relayToSession ? ((IEventConsumer)this).HandleEvent(eventType, parameters, cancellationToken) : Task.CompletedTask;
var sessionEventTask = relayToSession ? ((IEventConsumer)this).HandleEvent(eventType, parameters, false, cancellationToken) : Task.CompletedTask;
await Task.WhenAll(
eventConsumer.HandleEvent(eventType, parameters, cancellationToken),
eventConsumer.HandleEvent(eventType, parameters, false, cancellationToken),
sessionEventTask);
}
catch (JobException ex)
@@ -1005,7 +1005,7 @@ namespace Tgstation.Server.Host.Components.Watchdog
return;
if (!graceful)
{
var eventTask = HandleEvent(
var eventTask = HandleEventImpl(
releaseServers
? EventType.WatchdogDetach
: EventType.WatchdogShutdown,
@@ -17,7 +17,6 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
@@ -337,6 +336,9 @@ namespace Tgstation.Server.Host.Core
services.AddSingleton<INetworkPromptReaper, PosixNetworkPromptReaper>();
services.AddSingleton<IHostedService, PosixSignalHandler>();
services.AddSingleton<SystemDManager>();
services.AddSingleton<IHostedService>(x => x.GetRequiredService<SystemDManager>());
}
// configure file transfer services
@@ -421,14 +423,6 @@ namespace Tgstation.Server.Host.Core
logger.LogDebug("Content Root: {contentRoot}", hostingEnvironment.ContentRootPath);
logger.LogTrace("Web Root: {webRoot}", hostingEnvironment.WebRootPath);
// attempt to restart the server if the configuration changes
if (serverControl.WatchdogPresent)
ChangeToken.OnChange(Configuration.GetReloadToken, () =>
{
logger.LogInformation("Configuration change detected");
serverControl.Restart();
});
// setup the HTTP request pipeline
// Add additional logging context to the request
applicationBuilder.UseAdditionalRequestLoggingContext(swarmConfiguration);
+13 -2
View File
@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -48,14 +49,24 @@ namespace Tgstation.Server.Host
{
ArgumentNullException.ThrowIfNull(args);
// need to shove this arg in to disable config reloading unless a user specifically overrides it
if (!args.Any(arg => arg.Contains("hostBuilder:reloadConfigOnChange", StringComparison.OrdinalIgnoreCase))
&& String.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("hostBuilder__reloadConfigOnChange")))
{
var oldArgs = args;
args = new string[oldArgs.Length + 1];
Array.Copy(oldArgs, args, oldArgs.Length);
args[oldArgs.Length] = "--hostBuilder:reloadConfigOnChange=false";
}
var basePath = IOManager.ResolvePath();
IHostBuilder CreateDefaultBuilder() => Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
builder.SetBasePath(basePath);
builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: true)
.AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: true);
builder.AddYamlFile("appsettings.yml", optional: true, reloadOnChange: false)
.AddYamlFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.yml", optional: true, reloadOnChange: false);
// reorganize the builder so our yaml configs don't override the env/cmdline configs
// values obtained via debugger
@@ -127,5 +127,15 @@ namespace Tgstation.Server.Host.System
IntPtr expParam,
IntPtr userStreamParam,
IntPtr callbackParam);
/// <summary>
/// See https://www.freedesktop.org/software/systemd/man/sd_notify.html.
/// </summary>
#pragma warning disable IDE0079
#pragma warning disable CA2101 // https://github.com/dotnet/roslyn-analyzers/issues/5479#issuecomment-1603665900
[DllImport("libsystemd.so.0", CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true)]
public static extern int sd_notify(int unset_environment, [MarshalAs(UnmanagedType.LPUTF8Str)] string state);
#pragma warning restore CA2101
#pragma warning restore IDE0079
}
}
@@ -0,0 +1,217 @@
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Mono.Unix;
using Tgstation.Server.Host.Components;
using Tgstation.Server.Host.Core;
using Tgstation.Server.Host.Extensions;
namespace Tgstation.Server.Host.System
{
/// <summary>
/// Implements the SystemD notify service protocol.
/// </summary>
sealed class SystemDManager : IHostedService, IRestartHandler, IDisposable
{
/// <summary>
/// The <see cref="IHostApplicationLifetime"/> for the <see cref="SystemDManager"/>.
/// </summary>
readonly IHostApplicationLifetime applicationLifetime;
/// <summary>
/// The <see cref="IInstanceManager"/> for the <see cref="SystemDManager"/>.
/// </summary>
readonly IInstanceManager instanceManager;
/// <summary>
/// The <see cref="IRestartRegistration"/> for the <see cref="SystemDManager"/>.
/// </summary>
readonly IRestartRegistration restartRegistration;
/// <summary>
/// The <see cref="ILogger"/> for the <see cref="SystemDManager"/>.
/// </summary>
readonly ILogger<SystemDManager> logger;
/// <summary>
/// The <see cref="CancellationTokenSource"/> for <see cref="runTask"/>.
/// </summary>
readonly CancellationTokenSource watchdogCts;
/// <summary>
/// The main task executing in the <see cref="SystemDManager"/>.
/// </summary>
Task runTask;
/// <summary>
/// If TGS is going to restart.
/// </summary>
bool restartInProgress;
/// <summary>
/// Initializes a new instance of the <see cref="SystemDManager"/> class.
/// </summary>
/// <param name="applicationLifetime">The value of <see cref="applicationLifetime"/>.</param>
/// <param name="instanceManager">The value of <see cref="instanceManager"/>.</param>
/// <param name="serverControl">The <see cref="IServerControl"/> used to create the <see cref="restartRegistration"/>.</param>
/// <param name="logger">The value of <see cref="ILogger"/>.</param>
public SystemDManager(
IHostApplicationLifetime applicationLifetime,
IInstanceManager instanceManager,
IServerControl serverControl,
ILogger<SystemDManager> logger)
{
this.applicationLifetime = applicationLifetime ?? throw new ArgumentNullException(nameof(applicationLifetime));
this.instanceManager = instanceManager ?? throw new ArgumentNullException(nameof(instanceManager));
ArgumentNullException.ThrowIfNull(serverControl);
this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
restartRegistration = serverControl.RegisterForRestart(this);
try
{
watchdogCts = new CancellationTokenSource();
}
catch
{
restartRegistration.Dispose();
throw;
}
}
/// <inheritdoc />
public void Dispose()
{
restartRegistration.Dispose();
watchdogCts.Dispose();
}
/// <inheritdoc />
public Task HandleRestart(Version updateVersion, bool handlerMayDelayShutdownWithExtremelyLongRunningTasks, CancellationToken cancellationToken)
{
// If this is set, we know a gracefule SHUTDOWN was requested
restartInProgress = !handlerMayDelayShutdownWithExtremelyLongRunningTasks;
return Task.CompletedTask;
}
/// <inheritdoc />
public Task StartAsync(CancellationToken cancellationToken)
{
if (SendSDNotify("RELOADING=1"))
{
logger.LogDebug("SystemD detected");
runTask = RunAsync(watchdogCts.Token);
}
else
{
logger.LogDebug("SystemD not detected");
runTask = Task.CompletedTask;
}
return Task.CompletedTask;
}
/// <inheritdoc />
public async Task StopAsync(CancellationToken cancellationToken)
{
watchdogCts.Cancel();
await runTask.WithToken(cancellationToken);
}
/// <summary>
/// Runs the <see cref="SystemDManager"/>.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> for the operation.</param>
/// <returns>A <see cref="Task"/> representing the running operation.</returns>
async Task RunAsync(CancellationToken cancellationToken)
{
if (applicationLifetime.ApplicationStarted.IsCancellationRequested)
throw new InvalidOperationException("RunAsync called after application started!");
logger.LogTrace("Installing lifetime handlers...");
var readyCounts = 0;
void CheckReady()
{
if (Interlocked.Increment(ref readyCounts) < 2)
return;
SendSDNotify("READY=1");
}
applicationLifetime.ApplicationStarted.Register(() => CheckReady());
applicationLifetime.ApplicationStopping.Register(
() => SendSDNotify(
restartInProgress
? "RELOADING=1"
: "STOPPING=1"));
try
{
await instanceManager.Ready.WithToken(cancellationToken);
CheckReady();
var watchdogUsec = Environment.GetEnvironmentVariable("WATCHDOG_USEC");
if (String.IsNullOrWhiteSpace(watchdogUsec))
{
logger.LogDebug("WATCHDOG_USEC not present, not starting watchdog loop");
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;
while (!cancellationToken.IsCancellationRequested)
{
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!");
}
}
catch (OperationCanceledException ex)
{
logger.LogTrace(ex, "Watchdog loop cancelled!");
}
catch (Exception ex)
{
logger.LogError(ex, "Watchdog loop crashed!");
}
logger.LogDebug("Exited watchdog loop");
}
/// <summary>
/// Send a sd_notify <paramref name="command"/>.
/// </summary>
/// <param name="command">The <see cref="string"/> to send via sd_notify.</param>
/// <returns><see langword="true"/> if the command succeeded, <see langword="false"/> otherwise.</returns>
bool SendSDNotify(string command)
{
logger.LogTrace("Sending sd_notify {message}...", command);
var result = NativeMethods.sd_notify(0, command);
if (result > 0)
return true;
if (result < 0)
logger.LogError(new UnixIOException(result), "sd_notify READY=1 failed!");
else
logger.LogTrace("Could not send sd_notify {message}. Socket closed!", command);
return false;
}
}
}
+53 -46
View File
@@ -1,59 +1,66 @@
General:
MinimumPasswordLength: 15
GitHubAccessToken: null
SetupWizardMode: AutoDetect
ByondTopicTimeout: 5000
RestartTimeoutMinutes: 1
ApiPort: 5000
UseBasicWatchdog: false
UserLimit: 100
UserGroupLimit: 25
InstanceLimit: 10
ValidInstancePaths:
HostApiDocumentation: false
SkipAddingByondFirewallException: false
DeploymentDirectoryCopyTasksPerCore: 100
# ConfigVersion: # Basic semver. Differs from TGS version to version. See changelog for current version
MinimumPasswordLength: 15 # Minimum TGS user password length
GitHubAccessToken: # GitHub personal access token with no scopes used to bypass rate-limits
SetupWizardMode: AutoDetect # If the interactive TGS setup wizard should run
ByondTopicTimeout: 5000 # Timeout for BYOND /world/Topic() calls in milliseconds
RestartTimeoutMinutes: 1 # Timeout for server restarts after requested by SIGTERM or the HTTP API
ApiPort: 5000 # Port the HTTP API is hosted on
UseBasicWatchdog: false # The basic watchdog hard restarts DreamDaemon when /world/proc/TgsReboot() is called in the DMAPI if a new deployment is available
UserLimit: 100 # Maximum number of allowed users
UserGroupLimit: 25 # Maximum number of allowed groups
InstanceLimit: 10 # Maximum number of allowed instances
ValidInstancePaths: # An array of directories instances may be created in (either directly or as a subdirectory). null removes the restriction
HostApiDocumentation: false # Make HTTP API documentation available at /swagger/v1/swagger.json
SkipAddingByondFirewallException: false # Windows Only: Prevent running netsh.exe to add a firewall exception for installed DreamDaemon binaries
DeploymentDirectoryCopyTasksPerCore: 100 # Maximum number of concurrent file copy operations PER available CPU core
Session:
HighPriorityLiveDreamDaemon: false
LowPriorityDeploymentProcesses: true
HighPriorityLiveDreamDaemon: false # If DreamDaemon instances should run as higher priority processes
LowPriorityDeploymentProcesses: true # If TGS Deployments should run as lower priority processes
FileLogging:
Directory:
Disable: false
LogLevel: Debug
MicrosoftLogLevel: Warning
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
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:
IncludeScopes: false
Debug:
LogLevel:
Default: Debug
Microsoft: Information
Default: Debug # Level of debugger logging verbosity. Can be one of Trace, Debug, Information, Warning, Error, or Critical.
Microsoft: Information # 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
Console:
LogLevel:
Default: Trace
Microsoft: Warning
Default: Trace # Level of stdout logging verbosity. Can be one of Trace, Debug, Information, Warning, Error, or Critical.
Microsoft: Warning # Level of stdout verbosity from Microsoft dependecies (i.e. webserver, database object relational mapper, etc...). Can be one of Trace, Debug, Information, Warning, Error, or Critical
ControlPanel:
Enable: false
Channel: https://tgstation.github.io/tgstation-server-webpanel/api/${Major}.${Minor}.${Patch}
AllowAnyOrigin: false
AllowedOrigins: []
PublicPath:
Enable: false # If the web control panel is hosted alongside the server
Channel: https://tgstation.github.io/tgstation-server-webpanel/api/${Major}.${Minor}.${Patch} # Channel for live web control panel updates. The tokens ${Major}, ${Minor}, and ${Patch} are substituted for the version of the HTTP API TGS was built with
AllowAnyOrigin: false # Enable the `Access-Control-Allow-Origin: *` header for HTTP responses
AllowedOrigins: [] # Explict list of origins for `Access-Control-Allow-Origin:` HTTP header. Ignored if AllowAnyOrigin is true
PublicPath: # Used if TGS is not hosted at the website root. If TGS is hosted under `https://domain.com/tgs`, this should be `/tgs`
Updates:
GitHubRepositoryId: 92952846
GitTagPrefix: tgstation-server-v
UpdatePackageAssetName: ServerUpdatePackage.zip
GitHubRepositoryId: 92952846 # GitHub repostiory ID where TGS updates can be found in releases
GitTagPrefix: tgstation-server-v # Git tag prefix used for locating server update releases
UpdatePackageAssetName: ServerUpdatePackage.zip # Name of the .zip file asset that contains the server update
Database:
DropDatabase: false
DatabaseType: SqlServer
ResetAdminPassword: false
ServerVersion:
ConnectionString: Data Source=(local);Initial Catalog=TGS;Integrated Security=True
DatabaseType: SqlServer # The database type TGS connects to
ServerVersion: # The version of the database being connected to, generally not required to be specified
ConnectionString: Data Source=(local);Initial Catalog=TGS;Integrated Security=True # The connection string used to establish the database connection. Format varies for each DatabaseType
DropDatabase: false # DANGEROUS! Causes TGS to recreate its database on startup. Must be unset manually
ResetAdminPassword: false # DANGEROUS! Causes TGS to reset the `Admin` user password back to its default value on startup. Must be unset manually.
Security:
TokenExpiryMinutes: 15
TokenClockSkewMinutes: 1
TokenSigningKeyByteAmount: 256
CustomTokenSigningKeyBase64:
TokenExpiryMinutes: 15 # Length of time in minutes a login session token is valid for
TokenClockSkewMinutes: 1 # Clock skew allowance for validating loging tokens
TokenSigningKeyByteAmount: 256 # Length of generated token signing key in bytes. Ignored if CustomTokenSigningKeyBase64 is set
CustomTokenSigningKeyBase64: #
OAuth:
GitHub:
Discord:
TGForums:
Keycloak:
# Example:
# RedirectUrl: # Return URL for OAuth handshake. For a server hosted at `https://domain.com/tgs`, this should be in the format `https://domain.com/tgs/app/`
# ClientId: # OAuth client ID
# ClientSecret: # OAuth client secret
# ServerUrl: # Only used by Keycloak and InvisionCommunity. Server URL (Includes Keycloak realm)
# UserInformationUrlOverride: # Not supported by GitHub. Overrides the URL TGS uses to retrieve a user's information
GitHub: # https://github.com OAuth configuration
Discord: # https://discord.com OAuth configuration
TGForums: # https://tgstation13.org OAuth configuration
Keycloak: # Keycloak OAuth configuration.
InvisionCommunity: # Invision Community OAuth configuration.
+1
View File
@@ -206,6 +206,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deb", "deb", "{457A1F89-620
ProjectSection(SolutionItems) = preProject
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
build\package\deb\wrap_gpg.sh = build\package\deb\wrap_gpg.sh
EndProjectSection
EndProject