using Docker.DotNet; using Docker.DotNet.Models; using CaddyManager.Contracts.Configurations.Docker; using CaddyManager.Contracts.Configurations; using CaddyManager.Contracts.Docker; namespace CaddyManager.Services.Docker; /// public class DockerService(IConfigurationsService configurationsService) : IDockerService { private DockerServiceConfiguration Configuration => configurationsService.Get(); /// /// Method to get the container id of the Caddy container by the name configured /// /// private async Task 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(); /// 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()); } /// public async Task 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 }; } } }