Files
CaddyManager/CaddyManager.Services/Docker/DockerService.cs
ebolo d0687c9134
All checks were successful
Caddy Manager CI build / docker (push) Successful in 11m33s
feat(docker): Gracefully reload Caddy configuration
2026-07-26 11:39:59 +07:00

100 lines
3.5 KiB
C#

using Docker.DotNet;
using Docker.DotNet.Models;
using CaddyManager.Contracts.Configurations.Docker;
using CaddyManager.Contracts.Configurations;
using CaddyManager.Contracts.Docker;
namespace CaddyManager.Services.Docker;
/// <inheritdoc />
public class DockerService(IConfigurationsService configurationsService) : IDockerService
{
private DockerServiceConfiguration Configuration => configurationsService.Get<DockerServiceConfiguration>();
/// <summary>
/// Method to get the container id of the Caddy container by the name configured
/// </summary>
/// <returns></returns>
private async Task<string> GetCaddyContainerId(IDockerClient client)
{
var containers = await client.Containers.ListContainersAsync(new ContainersListParameters
{
All = true
});
return containers.FirstOrDefault(container => container.Names.Contains($"/{Configuration.CaddyContainerName}"))
?.ID ?? string.Empty;
}
private IDockerClient CreateClient() =>
new DockerClientConfiguration(new Uri(Configuration.DockerHostWithEnvCheck)).CreateClient();
/// <inheritdoc />
public async Task RestartCaddyContainerAsync()
{
using var client = CreateClient();
var containerId = await GetCaddyContainerId(client);
if (string.IsNullOrEmpty(containerId)) return;
await client.Containers.RestartContainerAsync(containerId, new ContainerRestartParameters());
}
/// <inheritdoc />
public async Task<CaddyReloadResponse> ReloadCaddyContainerAsync()
{
try
{
using var client = CreateClient();
var containerId = await GetCaddyContainerId(client);
if (string.IsNullOrEmpty(containerId))
{
return new CaddyReloadResponse
{
Message = $"Caddy container '{Configuration.CaddyContainerName}' was not found"
};
}
var exec = await client.Exec.ExecCreateContainerAsync(containerId, new ContainerExecCreateParameters
{
Cmd = ["caddy", "reload", "--config", Configuration.CaddyConfigPathInContainer],
AttachStdout = true,
AttachStderr = true
});
string stdout, stderr;
using (var stream = await client.Exec.StartAndAttachContainerExecAsync(exec.ID, false))
{
(stdout, stderr) = await stream.ReadOutputToEndAsync(CancellationToken.None);
}
var inspection = await client.Exec.InspectContainerExecAsync(exec.ID);
if (inspection.ExitCode == 0)
{
return new CaddyReloadResponse { Success = true };
}
// Caddy reports errors on stderr, interleaved with its structured JSON progress logs which are noise here
var output = string.Join(Environment.NewLine, $"{stderr}{Environment.NewLine}{stdout}"
.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Where(line => !line.StartsWith('{')));
return new CaddyReloadResponse
{
Message = string.IsNullOrWhiteSpace(output)
? $"Caddy reload failed with exit code {inspection.ExitCode}"
: output.Trim()
};
}
catch (Exception e)
{
return new CaddyReloadResponse { Message = e.Message };
}
}
}