feat: support restart caddy docker container

This commit is contained in:
2025-01-24 23:31:12 +07:00
parent 7ac609e9f6
commit a51b58561a
21 changed files with 158 additions and 33 deletions

View File

@@ -6,6 +6,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<LangVersion>13</LangVersion>
<ContainerRepository>ebolo/caddy-manager</ContainerRepository>
</PropertyGroup>
<ItemGroup>
@@ -22,7 +23,14 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Repositories\" />
<AdditionalFiles Include="Components\Pages\Caddy\CaddyfileEditor\CaddyfileEditor.razor" />
<AdditionalFiles Include="Components\Pages\Caddy\ReverseProxies\ReverseProxiesPage.razor" />
<AdditionalFiles Include="Components\Pages\Caddy\ReverseProxies\ReverseProxyItem.razor" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Components\Pages\ReverseProxies\ReverseProxiesPage.razor" />
<_ContentIncludedByDefault Remove="Components\Pages\ReverseProxies\ReverseProxyItem.razor" />
</ItemGroup>
</Project>

View File

@@ -15,7 +15,7 @@
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="@_drawer.ToggleDrawer" />
<MudText Typo="Typo.h6">Caddy Manager</MudText>
<MudSpacer />
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit" Href="https://github.com/MudBlazor/MudBlazor" Target="_blank" />
<MudIconButton Icon="@Icons.Custom.Brands.GitHub" Color="Color.Inherit" Href="https://pikachu-gitea.duydao.org/ebolo/CaddyManager" Target="_blank" />
</MudAppBar>
<NavigationDrawer @ref="_drawer"/>
<MudMainContent Class="pt-16 px-16">

View File

@@ -8,7 +8,5 @@
</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="/caddyfile" Icon="@Icons.Material.Filled.Language">Global Caddyfile
</MudNavLink>
<MudNavLink Match="NavLinkMatch.All" Href="/settings" Icon="@Icons.Material.Filled.Settings">Settings
</MudNavLink>
</MudNavMenu>
</MudDrawer>

View File

@@ -4,7 +4,7 @@ using CaddyManager.Models.Caddy;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace CaddyManager.Components.Pages.CaddyfileEditor;
namespace CaddyManager.Components.Pages.Caddy.CaddyfileEditor;
public partial class CaddyfileEditor : ComponentBase
{

View File

@@ -3,7 +3,7 @@ using CaddyManager.Contracts.Caddy;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace CaddyManager.Components.Pages;
namespace CaddyManager.Components.Pages.Caddy;
public partial class CaddyfilePage : ComponentBase
{
@@ -28,6 +28,7 @@ public partial class CaddyfilePage : ComponentBase
AutomaticLayout = true,
Language = "plaintext",
Value = _caddyConfigurationContent,
Theme = "vs-dark",
};
}
@@ -47,6 +48,6 @@ public partial class CaddyfilePage : ComponentBase
private void Cancel()
{
// CaddyService.GetCaddyGlobalConfigurationContent();
_codeEditor.SetValue(_caddyConfigurationContent);
}
}

View File

@@ -3,7 +3,7 @@
<PageTitle>Reverse proxy configurations</PageTitle>
<MudContainer Class="d-flex flex-row flex-grow-1 gap-4">
<MudContainer Class="d-flex flex-row flex-grow-1 gap-4 align-center">
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add"
OnClick="NewReverseProxy">New...
</MudButton>
@@ -11,6 +11,13 @@
Disabled="@(_selectedCaddyConfigurations.Count <= 0)"
OnClick="Delete">Delete
</MudButton>
<MudButton Variant="Variant.Filled" Color="Color.Default" StartIcon="@Icons.Material.Filled.Refresh"
OnClick="RestartCaddy">Restart Caddy
</MudButton>
@if (_isProcessing)
{
<MudProgressCircular Color="Color.Primary" Indeterminate="true" Size="Size.Small"/>
}
</MudContainer>
<MudList T="string" Style="padding-top: 16px;" SelectionMode="SelectionMode.MultiSelection"
@bind-SelectedValues="_selectedCaddyConfigurations">

View File

@@ -1,17 +1,22 @@
using CaddyManager.Contracts.Caddy;
using CaddyManager.Contracts.Docker;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace CaddyManager.Components.Pages.ReverseProxies;
namespace CaddyManager.Components.Pages.Caddy.ReverseProxies;
public partial class ReverseProxiesPage : ComponentBase
{
private bool _isProcessing;
private List<string> _availableCaddyConfigurations = [];
private IReadOnlyCollection<string> _selectedCaddyConfigurations = [];
[Inject]
private ICaddyService CaddyService { get; set; } = null!;
[Inject]
private IDockerService DockerService { get; set; } = null!;
[Inject]
private IDialogService DialogService { get; set; } = null!;
@@ -59,6 +64,9 @@ public partial class ReverseProxiesPage : ComponentBase
StateHasChanged();
}
/// <summary>
/// Have the selected configurations be deleted
/// </summary>
private void Delete()
{
var response = CaddyService.DeleteCaddyConfigurations(_selectedCaddyConfigurations.ToList());
@@ -75,4 +83,26 @@ public partial class ReverseProxiesPage : ComponentBase
Snackbar.Add(response.Message, Severity.Error);
}
}
/// <summary>
/// Restart the Caddy container
/// </summary>
/// <returns></returns>
private async Task RestartCaddy()
{
try
{
_isProcessing = true;
StateHasChanged();
Snackbar.Add("Restarting Caddy container", Severity.Info);
await DockerService.RestartCaddyContainerAsync();
Snackbar.Add("Caddy container restarted successfully", Severity.Success);
_isProcessing = false;
StateHasChanged();
}
catch
{
Snackbar.Add("Failed to restart the Caddy container", Severity.Error);
}
}
}

View File

@@ -2,7 +2,7 @@ using CaddyManager.Contracts.Caddy;
using Microsoft.AspNetCore.Components;
using MudBlazor;
namespace CaddyManager.Components.Pages.ReverseProxies;
namespace CaddyManager.Components.Pages.Caddy.ReverseProxies;
public partial class ReverseProxyItem : ComponentBase
{

View File

@@ -1,21 +0,0 @@
@page "/settings"
@using CaddyManager.Contracts.Caddy
@inject ICaddyService CaddyService
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<MudButton Variant="Variant.Filled" Color="Color.Primary" @onclick="IncrementCount">Click me</MudButton>
@code {
private int currentCount = 0;
private void IncrementCount()
{
Console.WriteLine(string.Join('\n', CaddyService.GetExistingCaddyConfigurations()));
}
}

View File

@@ -0,0 +1,25 @@
namespace CaddyManager.Configurations.Docker;
/// <summary>
/// Configuration for the Docker service
/// </summary>
public class DockerServiceConfiguration
{
public const string Docker = "Docker";
/// <summary>
/// Name of the Caddy container to be controlled (i.e restart)
/// </summary>
public string CaddyContainerName { get; set; } = "caddy";
/// <summary>
/// Uri to the Docker host
/// </summary>
public string DockerHost { get; set; } = "unix:///var/run/docker.sock";
/// <summary>
/// Returns the Docker host with environment check. If the environment variable DOCKER_HOST is set, it will return
/// that value, otherwise it will return the value of DockerHost
/// </summary>
public string DockerHostWithEnvCheck => Environment.GetEnvironmentVariable("DOCKER_HOST") ?? DockerHost;
}

View File

@@ -1,4 +1,5 @@
using CaddyManager.Configurations.Caddy;
using CaddyManager.Configurations.Docker;
namespace CaddyManager.Contracts.Configurations;
@@ -11,4 +12,9 @@ public interface IConfigurationsService
/// Configurations for Caddy service
/// </summary>
CaddyServiceConfigurations CaddyServiceConfigurations { get; }
/// <summary>
/// Configurations for Docker service
/// </summary>
DockerServiceConfiguration DockerServiceConfiguration { get; }
}

View File

@@ -0,0 +1,13 @@
namespace CaddyManager.Contracts.Docker;
/// <summary>
/// Contract for the service to interact with Docker
/// </summary>
public interface IDockerService
{
/// <summary>
/// Method to help restart the Caddy container
/// </summary>
/// <returns></returns>
Task RestartCaddyContainerAsync();
}

View File

@@ -12,7 +12,7 @@ builder.Services
// Auto register all the Services, Repositories that we have had within the code base
builder.Services.RegisterAssemblyPublicNonGenericClasses()
.Where(t => t.Name.EndsWith("Service") || t.Name.EndsWith("Repository"))
.Where(t => t.Name.EndsWith("Service"))
.AsPublicImplementedInterfaces();
builder.Services.AddSignalR(e => { e.MaximumReceiveMessageSize = 102400000; });

View File

@@ -3,7 +3,7 @@ using CaddyManager.Contracts.Caddy;
using CaddyManager.Contracts.Configurations;
using CaddyManager.Models.Caddy;
namespace CaddyManager.Services;
namespace CaddyManager.Services.Caddy;
/// <inheritdoc />
public class CaddyService(IConfigurationsService configurationsService) : ICaddyService

View File

@@ -1,4 +1,5 @@
using CaddyManager.Configurations.Caddy;
using CaddyManager.Configurations.Docker;
using CaddyManager.Contracts.Configurations;
using NetCore.AutoRegisterDi;
@@ -12,4 +13,8 @@ public class ConfigurationsService(IConfiguration configuration) : IConfiguratio
public CaddyServiceConfigurations CaddyServiceConfigurations =>
configuration.GetSection(CaddyServiceConfigurations.Caddy).Get<CaddyServiceConfigurations>() ??
new CaddyServiceConfigurations();
public DockerServiceConfiguration DockerServiceConfiguration =>
configuration.GetSection(DockerServiceConfiguration.Docker).Get<DockerServiceConfiguration>() ??
new DockerServiceConfiguration();
}

View File

@@ -0,0 +1,48 @@
using CaddyManager.Configurations.Docker;
using CaddyManager.Contracts.Configurations;
using CaddyManager.Contracts.Docker;
using Docker.DotNet;
using Docker.DotNet.Models;
namespace CaddyManager.Services.Docker;
/// <inheritdoc />
public class DockerService(IConfigurationsService configurationsService) : IDockerService
{
private DockerServiceConfiguration Configuration => configurationsService.DockerServiceConfiguration;
/// <summary>
/// Method to get the container id of the Caddy container by the name configured
/// </summary>
/// <returns></returns>
private async Task<string> GetCaddyContainerId()
{
var client = new DockerClientConfiguration(new Uri(Configuration.DockerHostWithEnvCheck)).CreateClient();
if (client == null) return string.Empty;
var containers = await client.Containers.ListContainersAsync(new ContainersListParameters
{
All = true
});
return containers.FirstOrDefault(container => container.Names.Contains($"/{Configuration.CaddyContainerName}"))
?.ID ?? string.Empty;
}
/// <inheritdoc />
public async Task RestartCaddyContainerAsync()
{
var containerId = await GetCaddyContainerId();
if (string.IsNullOrEmpty(containerId)) return;
var client = new DockerClientConfiguration(new Uri(Configuration.DockerHostWithEnvCheck)).CreateClient();
if (client != null)
{
await client.Containers.RestartContainerAsync(containerId, new ContainerRestartParameters());
}
}
}

View File

@@ -8,5 +8,9 @@
"AllowedHosts": "*",
"Caddy": {
"ConfigDir": "/root/compose/caddy/config"
},
"Docker": {
"CaddyContainerName": "caddy",
"DockerHost": "unix:///var/run/docker.sock"
}
}

View File

@@ -11,4 +11,5 @@
.caddy-file-editor .monaco-editor {
overflow: hidden;
border-radius: inherit;
padding: 8px;
}