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

@@ -48,26 +48,20 @@
</StackPanel>
</Expander>
<!-- SMB / CIFS credentials (per-instance, defaults from global settings) -->
<Expander Header="SMB / CIFS credentials">
<!-- NFS volume settings (per-instance, defaults from global settings) -->
<Expander Header="NFS volume settings">
<StackPanel Spacing="8" Margin="0,8,0,0">
<TextBlock Text="CIFS Server" FontSize="12" />
<TextBox Text="{Binding CifsServer}" Watermark="e.g. 192.168.1.100" />
<TextBlock Text="NFS Server" FontSize="12" />
<TextBox Text="{Binding NfsServer}" Watermark="e.g. 192.168.1.100" />
<TextBlock Text="Share Name" FontSize="12" />
<TextBox Text="{Binding CifsShareName}" Watermark="e.g. u548897-sub1" />
<TextBlock Text="Export Path" FontSize="12" />
<TextBox Text="{Binding NfsExport}" Watermark="e.g. /srv/nfs" />
<TextBlock Text="Share Folder (optional)" FontSize="12" />
<TextBox Text="{Binding CifsShareFolder}" Watermark="e.g. ots_cms (leave empty for share root)" />
<TextBlock Text="Export Folder (optional)" FontSize="12" />
<TextBox Text="{Binding NfsExportFolder}" Watermark="e.g. ots_cms (leave empty for export root)" />
<TextBlock Text="Username" FontSize="12" />
<TextBox Text="{Binding CifsUsername}" Watermark="SMB username" />
<TextBlock Text="Password" FontSize="12" />
<TextBox Text="{Binding CifsPassword}" PasswordChar="●" Watermark="SMB password" />
<TextBlock Text="Extra Options" FontSize="12" />
<TextBox Text="{Binding CifsExtraOptions}" Watermark="file_mode=0777,dir_mode=0777" />
<TextBlock Text="Extra Mount Options" FontSize="12" />
<TextBox Text="{Binding NfsExtraOptions}" Watermark="Additional options after nfsvers=4,proto=tcp" />
</StackPanel>
</Expander>
@@ -102,46 +96,95 @@
IsVisible="{Binding DeployOutput.Length}" />
</StackPanel>
<!-- ══ RIGHT COLUMN — live resource preview ══ -->
<Border Grid.Column="2"
Background="#1e1e2e"
CornerRadius="8"
Padding="16,14"
VerticalAlignment="Top">
<StackPanel Spacing="6">
<TextBlock Text="Resource Preview" FontSize="14" FontWeight="SemiBold"
Foreground="#cdd6f4" Margin="0,0,0,8" />
<!-- ══ RIGHT COLUMN — tabbed preview ══ -->
<TabControl Grid.Column="2" VerticalAlignment="Top">
<TextBlock Text="Stack" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewStackName}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#89b4fa" Margin="0,0,0,6" />
<!-- Tab 1: Resource preview -->
<TabItem Header="Resource Preview">
<Border Background="#1e1e2e"
CornerRadius="8"
Padding="16,14">
<StackPanel Spacing="6">
<TextBlock Text="Resource Preview" FontSize="14" FontWeight="SemiBold"
Foreground="#cdd6f4" Margin="0,0,0,8" />
<TextBlock Text="Services" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewServiceWeb}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" />
<TextBlock Text="{Binding PreviewServiceCache}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" />
<TextBlock Text="{Binding PreviewServiceChart}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" />
<TextBlock Text="{Binding PreviewServiceNewt}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" Margin="0,0,0,6" />
<TextBlock Text="Stack" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewStackName}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#89b4fa" Margin="0,0,0,6" />
<TextBlock Text="Network" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewNetwork}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#94e2d5" Margin="0,0,0,6" />
<TextBlock Text="Services" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewServiceWeb}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" />
<TextBlock Text="{Binding PreviewServiceCache}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" />
<TextBlock Text="{Binding PreviewServiceChart}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" />
<TextBlock Text="{Binding PreviewServiceNewt}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#a6e3a1" Margin="0,0,0,6" />
<TextBlock Text="CIFS Volumes" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewVolCustom}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolBackup}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolLibrary}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolUserscripts}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolCaCerts}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" Margin="0,0,0,6" />
<TextBlock Text="Network" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewNetwork}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#94e2d5" Margin="0,0,0,6" />
<TextBlock Text="Docker Secret" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewSecret}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#fab387" Margin="0,0,0,6" />
<TextBlock Text="NFS Volumes" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewVolCustom}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolBackup}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolLibrary}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolUserscripts}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" />
<TextBlock Text="{Binding PreviewVolCaCerts}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#f5c2e7" Margin="0,0,0,6" />
<TextBlock Text="MySQL Database" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewMySqlDb}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#cba6f7" />
<TextBlock Text="{Binding PreviewMySqlUser}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#cba6f7" Margin="0,0,0,6" />
<TextBlock Text="Docker Secrets" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewSecret}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#fab387" />
<TextBlock Text="{Binding PreviewSecretUser}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#fab387" />
<TextBlock Text="{Binding PreviewSecretHost}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#fab387" />
<TextBlock Text="{Binding PreviewSecretPort}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#fab387" Margin="0,0,0,6" />
<TextBlock Text="CMS URL" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewCmsUrl}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#89dceb" />
</StackPanel>
</Border>
<TextBlock Text="MySQL Database" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewMySqlDb}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#cba6f7" />
<TextBlock Text="{Binding PreviewMySqlUser}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#cba6f7" Margin="0,0,0,6" />
<TextBlock Text="CMS URL" FontSize="11" Foreground="#6c7086" />
<TextBlock Text="{Binding PreviewCmsUrl}" FontFamily="Cascadia Mono, Consolas, monospace" FontSize="12" Foreground="#89dceb" />
</StackPanel>
</Border>
</TabItem>
<!-- Tab 2: Rendered compose YML -->
<TabItem Header="Compose YML">
<Border Background="#1e1e2e"
CornerRadius="8"
Padding="16,14">
<Grid RowDefinitions="Auto,*,Auto">
<!-- Load button -->
<Button Grid.Row="0"
Content="↻ Load / Refresh YML"
Command="{Binding LoadYmlPreviewCommand}"
IsEnabled="{Binding !IsLoadingYml}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="10,6"
Margin="0,0,0,8" />
<!-- YML text box -->
<TextBox Grid.Row="1"
Text="{Binding PreviewYml}"
IsReadOnly="True"
AcceptsReturn="True"
FontFamily="Cascadia Mono, Consolas, monospace"
FontSize="11"
MinHeight="320"
Watermark="Click 'Load / Refresh YML' to preview the rendered compose file…"
TextWrapping="NoWrap" />
<!-- Copy button -->
<Button Grid.Row="2"
Content="⎘ Copy to Clipboard"
Command="{Binding CopyYmlCommand}"
IsEnabled="{Binding HasPreviewYml}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
Padding="10,6"
Margin="0,8,0,0" />
</Grid>
</Border>
</TabItem>
</TabControl>
</Grid>
</ScrollViewer>

View File

@@ -18,6 +18,37 @@
<TextBlock DockPanel.Dock="Bottom" Text="{Binding StatusMessage}" Margin="0,8,0,0"
FontSize="12" Foreground="#a6adc8" />
<!-- Remote Nodes panel -->
<Border DockPanel.Dock="Bottom" Margin="0,12,0,0" Padding="8"
Background="#1e1e2e" CornerRadius="8"
MinHeight="120" MaxHeight="300">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Spacing="8" Margin="0,0,0,8">
<TextBlock Text="Cluster Nodes" FontSize="14" FontWeight="SemiBold" VerticalAlignment="Center" />
<Button Content="List Nodes" Command="{Binding ListNodesCommand}" />
<TextBlock Text="{Binding NodesStatusMessage}" FontSize="12"
Foreground="#a6adc8" VerticalAlignment="Center" Margin="8,0,0,0" />
</StackPanel>
<DataGrid ItemsSource="{Binding RemoteNodes}"
AutoGenerateColumns="False"
IsReadOnly="True"
GridLinesVisibility="Horizontal"
CanUserResizeColumns="True"
HeadersVisibility="Column">
<DataGrid.Columns>
<DataGridTextColumn Header="Hostname" Binding="{Binding Hostname}" Width="160" />
<DataGridTextColumn Header="IP Address" Binding="{Binding IpAddress}" Width="130" />
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="80" />
<DataGridTextColumn Header="Availability" Binding="{Binding Availability}" Width="100" />
<DataGridTextColumn Header="Manager Status" Binding="{Binding ManagerStatus}" Width="120" />
<DataGridTextColumn Header="Engine" Binding="{Binding EngineVersion}" Width="100" />
<DataGridTextColumn Header="ID" Binding="{Binding Id}" Width="200" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Border>
<!-- Edit panel (shown when editing) -->
<Border DockPanel.Dock="Right" Width="350" IsVisible="{Binding IsEditing}"
Background="#1e1e2e" CornerRadius="8" Padding="16" Margin="12,0,0,0">

View File

@@ -7,21 +7,13 @@
<DockPanel>
<!-- Toolbar -->
<StackPanel DockPanel.Dock="Top" Spacing="8" Margin="0,0,0,12">
<StackPanel Orientation="Horizontal" Spacing="8">
<ComboBox ItemsSource="{Binding AvailableHosts}"
SelectedItem="{Binding SelectedSshHost}"
PlaceholderText="Select SSH Host..."
Width="250">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Label}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Content="List Remote Stacks" Command="{Binding RefreshRemoteStacksCommand}" />
<StackPanel Orientation="Horizontal" Spacing="8">
<Button Content="Refresh" Command="{Binding LoadInstancesCommand}" />
<Button Content="Inspect" Command="{Binding InspectInstanceCommand}" />
<Button Content="Delete" Command="{Binding DeleteInstanceCommand}" />
<Button Content="Refresh" Command="{Binding LoadInstancesCommand}" />
<Button Content="Rotate DB Password" Command="{Binding RotateMySqlPasswordCommand}"
IsEnabled="{Binding !IsBusy}"
ToolTip.Tip="Generate a new MySQL password, update the Docker secret, and redeploy the stack." />
</StackPanel>
<StackPanel Orientation="Horizontal" Spacing="8">
@@ -57,25 +49,7 @@
</StackPanel>
</Border>
<!-- Remote stacks panel -->
<Border DockPanel.Dock="Bottom" MaxHeight="200"
IsVisible="{Binding RemoteStacks.Count}"
Background="#1e1e2e" CornerRadius="8" Padding="12" Margin="0,8,0,0">
<StackPanel Spacing="4">
<TextBlock Text="Remote Stacks" FontWeight="SemiBold" />
<ItemsControl ItemsSource="{Binding RemoteStacks}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding Name}" FontWeight="SemiBold" />
<Run Text="{Binding ServiceCount, StringFormat=' ({0} services)'}"
Foreground="#a6adc8" />
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
<!-- Remote stacks panel removed: all live stacks are shown in the main list below -->
<!-- Instance list -->
<DataGrid ItemsSource="{Binding Instances}"
@@ -85,13 +59,10 @@
GridLinesVisibility="Horizontal"
CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Stack" Binding="{Binding StackName}" Width="120" />
<DataGridTextColumn Header="Customer" Binding="{Binding CustomerName}" Width="120" />
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="80" />
<DataGridTextColumn Header="Server" Binding="{Binding CmsServerName}" Width="150" />
<DataGridTextColumn Header="Port" Binding="{Binding HostHttpPort}" Width="60" />
<DataGridTextColumn Header="Host" Binding="{Binding SshHost.Label}" Width="120" />
<DataGridTextColumn Header="Created" Binding="{Binding CreatedAt, StringFormat='{}{0:g}'}" Width="140" />
<DataGridTextColumn Header="Stack" Binding="{Binding StackName}" Width="150" />
<DataGridTextColumn Header="Abbrev" Binding="{Binding CustomerAbbrev}" Width="70" />
<DataGridTextColumn Header="Services" Binding="{Binding ServiceCount}" Width="70" />
<DataGridTextColumn Header="Host" Binding="{Binding HostLabel}" Width="150" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>

View File

@@ -20,7 +20,7 @@
<DataGridTextColumn Header="Time" Binding="{Binding Timestamp, StringFormat='{}{0:g}'}" Width="150" />
<DataGridTextColumn Header="Operation" Binding="{Binding Operation}" Width="100" />
<DataGridTextColumn Header="Status" Binding="{Binding Status}" Width="80" />
<DataGridTextColumn Header="Instance" Binding="{Binding Instance.StackName}" Width="120" />
<DataGridTextColumn Header="Stack" Binding="{Binding StackName}" Width="120" />
<DataGridTextColumn Header="Message" Binding="{Binding Message}" Width="*" />
<DataGridTextColumn Header="Duration" Binding="{Binding DurationMs, StringFormat='{}{0}ms'}" Width="80" />
</DataGrid.Columns>

View File

@@ -116,31 +116,25 @@
</StackPanel>
</Border>
<!-- ═══ CIFS Volumes ═══ -->
<!-- ═══ NFS Volumes ═══ -->
<Border Background="#1e1e2e" CornerRadius="8" Padding="16">
<StackPanel Spacing="8">
<TextBlock Text="CIFS Volumes" FontSize="16" FontWeight="SemiBold"
<TextBlock Text="NFS Volumes" FontSize="16" FontWeight="SemiBold"
Foreground="#cba6f7" Margin="0,0,0,4" />
<TextBlock Text="Network share settings for Docker volumes. Volumes will be mounted via CIFS."
<TextBlock Text="Network share settings for Docker volumes. Volumes will be mounted via NFS."
FontSize="12" Foreground="#6c7086" Margin="0,0,0,4" />
<TextBlock Text="CIFS Server (hostname/IP)" FontSize="12" />
<TextBox Text="{Binding CifsServer}" Watermark="nas.local" />
<TextBlock Text="NFS Server (hostname/IP)" FontSize="12" />
<TextBox Text="{Binding NfsServer}" Watermark="nas.local" />
<TextBlock Text="Share Name" FontSize="12" />
<TextBox Text="{Binding CifsShareName}" Watermark="u548897-sub1" />
<TextBlock Text="Export Path" FontSize="12" />
<TextBox Text="{Binding NfsExport}" Watermark="/srv/nfs" />
<TextBlock Text="Share Folder (optional)" FontSize="12" />
<TextBox Text="{Binding CifsShareFolder}" Watermark="ots_cms (leave empty for share root)" />
<TextBlock Text="Username" FontSize="12" />
<TextBox Text="{Binding CifsUsername}" Watermark="smbuser" />
<TextBlock Text="Password" FontSize="12" />
<TextBox Text="{Binding CifsPassword}" PasswordChar="●" />
<TextBlock Text="Export Folder (optional)" FontSize="12" />
<TextBox Text="{Binding NfsExportFolder}" Watermark="ots_cms (leave empty for export root)" />
<TextBlock Text="Extra Mount Options" FontSize="12" />
<TextBox Text="{Binding CifsOptions}" Watermark="file_mode=0777,dir_mode=0777" />
<TextBox Text="{Binding NfsOptions}" Watermark="Additional options after nfsvers=4,proto=tcp" />
</StackPanel>
</Border>
@@ -181,7 +175,7 @@
<TextBox Text="{Binding DefaultMySqlDbTemplate}" Watermark="{}{abbrev}_cms_db" />
<TextBlock Text="MySQL User Template" FontSize="12" />
<TextBox Text="{Binding DefaultMySqlUserTemplate}" Watermark="{}{abbrev}_cms" />
<TextBox Text="{Binding DefaultMySqlUserTemplate}" Watermark="{}{abbrev}_cms_user" />
<TextBlock Text="PHP Settings" FontSize="13" FontWeight="SemiBold" Margin="0,12,0,4" />