Add WAL file for database and log instance deployment failures
Some checks failed
Build and Publish Docker Image / build-and-push (push) Has been cancelled

This commit is contained in:
Matt Batchelder
2026-02-19 08:27:54 -05:00
parent 4a903bfd2a
commit adf1a2e4db
41 changed files with 2789 additions and 1297 deletions

View File

@@ -2,13 +2,12 @@ using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.DependencyInjection;
using MySqlConnector;
using OTSSignsOrchestrator.Core.Services;
namespace OTSSignsOrchestrator.Desktop.ViewModels;
/// <summary>
/// ViewModel for the Settings page — manages Git, MySQL, SMTP, Pangolin, CIFS,
/// ViewModel for the Settings page — manages Git, MySQL, SMTP, Pangolin, NFS,
/// and Instance Defaults configuration, persisted via SettingsService.
/// </summary>
public partial class SettingsViewModel : ObservableObject
@@ -41,13 +40,11 @@ public partial class SettingsViewModel : ObservableObject
// ── Pangolin ────────────────────────────────────────────────────────────
[ObservableProperty] private string _pangolinEndpoint = "https://app.pangolin.net";
// ── CIFS ────────────────────────────────────────────────────────────────
[ObservableProperty] private string _cifsServer = string.Empty;
[ObservableProperty] private string _cifsShareName = string.Empty;
[ObservableProperty] private string _cifsShareFolder = string.Empty;
[ObservableProperty] private string _cifsUsername = string.Empty;
[ObservableProperty] private string _cifsPassword = string.Empty;
[ObservableProperty] private string _cifsOptions = "file_mode=0777,dir_mode=0777";
// ── NFS ────────────────────────────────────────────────────────────────
[ObservableProperty] private string _nfsServer = string.Empty;
[ObservableProperty] private string _nfsExport = string.Empty;
[ObservableProperty] private string _nfsExportFolder = string.Empty;
[ObservableProperty] private string _nfsOptions = string.Empty;
// ── Instance Defaults ───────────────────────────────────────────────────
[ObservableProperty] private string _defaultCmsImage = "ghcr.io/xibosignage/xibo-cms:release-4.2.3";
@@ -57,7 +54,7 @@ public partial class SettingsViewModel : ObservableObject
[ObservableProperty] private string _defaultCmsServerNameTemplate = "{abbrev}.ots-signs.com";
[ObservableProperty] private string _defaultThemeHostPath = "/cms/{abbrev}-cms-theme-custom";
[ObservableProperty] private string _defaultMySqlDbTemplate = "{abbrev}_cms_db";
[ObservableProperty] private string _defaultMySqlUserTemplate = "{abbrev}_cms";
[ObservableProperty] private string _defaultMySqlUserTemplate = "{abbrev}_cms_user";
[ObservableProperty] private string _defaultPhpPostMaxSize = "10G";
[ObservableProperty] private string _defaultPhpUploadMaxFilesize = "10G";
[ObservableProperty] private string _defaultPhpMaxExecutionTime = "600";
@@ -100,13 +97,11 @@ public partial class SettingsViewModel : ObservableObject
// Pangolin
PangolinEndpoint = await svc.GetAsync(SettingsService.PangolinEndpoint, "https://app.pangolin.net");
// CIFS
CifsServer = await svc.GetAsync(SettingsService.CifsServer, string.Empty);
CifsShareName = await svc.GetAsync(SettingsService.CifsShareName, string.Empty);
CifsShareFolder = await svc.GetAsync(SettingsService.CifsShareFolder, string.Empty);
CifsUsername = await svc.GetAsync(SettingsService.CifsUsername, string.Empty);
CifsPassword = await svc.GetAsync(SettingsService.CifsPassword, string.Empty);
CifsOptions = await svc.GetAsync(SettingsService.CifsOptions, "file_mode=0777,dir_mode=0777");
// NFS
NfsServer = await svc.GetAsync(SettingsService.NfsServer, string.Empty);
NfsExport = await svc.GetAsync(SettingsService.NfsExport, string.Empty);
NfsExportFolder = await svc.GetAsync(SettingsService.NfsExportFolder, string.Empty);
NfsOptions = await svc.GetAsync(SettingsService.NfsOptions, string.Empty);
// Instance Defaults
DefaultCmsImage = await svc.GetAsync(SettingsService.DefaultCmsImage, "ghcr.io/xibosignage/xibo-cms:release-4.2.3");
@@ -116,7 +111,7 @@ public partial class SettingsViewModel : ObservableObject
DefaultCmsServerNameTemplate = await svc.GetAsync(SettingsService.DefaultCmsServerNameTemplate, "{abbrev}.ots-signs.com");
DefaultThemeHostPath = await svc.GetAsync(SettingsService.DefaultThemeHostPath, "/cms/{abbrev}-cms-theme-custom");
DefaultMySqlDbTemplate = await svc.GetAsync(SettingsService.DefaultMySqlDbTemplate, "{abbrev}_cms_db");
DefaultMySqlUserTemplate = await svc.GetAsync(SettingsService.DefaultMySqlUserTemplate, "{abbrev}_cms");
DefaultMySqlUserTemplate = await svc.GetAsync(SettingsService.DefaultMySqlUserTemplate, "{abbrev}_cms_user");
DefaultPhpPostMaxSize = await svc.GetAsync(SettingsService.DefaultPhpPostMaxSize, "10G");
DefaultPhpUploadMaxFilesize = await svc.GetAsync(SettingsService.DefaultPhpUploadMaxFilesize, "10G");
DefaultPhpMaxExecutionTime = await svc.GetAsync(SettingsService.DefaultPhpMaxExecutionTime, "600");
@@ -167,13 +162,11 @@ public partial class SettingsViewModel : ObservableObject
// Pangolin
(SettingsService.PangolinEndpoint, NullIfEmpty(PangolinEndpoint), SettingsService.CatPangolin, false),
// CIFS
(SettingsService.CifsServer, NullIfEmpty(CifsServer), SettingsService.CatCifs, false),
(SettingsService.CifsShareName, NullIfEmpty(CifsShareName), SettingsService.CatCifs, false),
(SettingsService.CifsShareFolder, NullIfEmpty(CifsShareFolder), SettingsService.CatCifs, false),
(SettingsService.CifsUsername, NullIfEmpty(CifsUsername), SettingsService.CatCifs, false),
(SettingsService.CifsPassword, NullIfEmpty(CifsPassword), SettingsService.CatCifs, true),
(SettingsService.CifsOptions, NullIfEmpty(CifsOptions), SettingsService.CatCifs, false),
// NFS
(SettingsService.NfsServer, NullIfEmpty(NfsServer), SettingsService.CatNfs, false),
(SettingsService.NfsExport, NullIfEmpty(NfsExport), SettingsService.CatNfs, false),
(SettingsService.NfsExportFolder, NullIfEmpty(NfsExportFolder), SettingsService.CatNfs, false),
(SettingsService.NfsOptions, NullIfEmpty(NfsOptions), SettingsService.CatNfs, false),
// Instance Defaults
(SettingsService.DefaultCmsImage, DefaultCmsImage, SettingsService.CatDefaults, false),
@@ -218,32 +211,21 @@ public partial class SettingsViewModel : ObservableObject
if (!int.TryParse(MySqlPort, out var port))
port = 3306;
var csb = new MySqlConnectionStringBuilder
{
Server = MySqlHost,
Port = (uint)port,
UserID = MySqlAdminUser,
Password = MySqlAdminPassword,
ConnectionTimeout = 10,
SslMode = MySqlSslMode.Preferred,
};
await using var connection = new MySqlConnection(csb.ConnectionString);
await connection.OpenAsync();
var docker = _services.GetRequiredService<IDockerCliService>();
var (connection, tunnel) = await docker.OpenMySqlConnectionAsync(
MySqlHost, port, MySqlAdminUser, MySqlAdminPassword);
await using var _ = connection;
using var __ = tunnel;
await using var cmd = connection.CreateCommand();
cmd.CommandText = "SELECT 1";
await cmd.ExecuteScalarAsync();
StatusMessage = $"MySQL connection successful ({MySqlHost}:{port}).";
}
catch (MySqlException ex)
{
StatusMessage = $"MySQL connection failed: {ex.Message}";
StatusMessage = $"MySQL connection successful ({MySqlHost}:{port} via SSH tunnel).";
}
catch (Exception ex)
{
StatusMessage = $"MySQL test error: {ex.Message}";
StatusMessage = $"MySQL connection failed: {ex.Message}";
}
finally
{