using MySqlConnector; using OTSSignsOrchestrator.Core.Models.DTOs; namespace OTSSignsOrchestrator.Core.Services; /// /// Abstraction for Docker CLI stack operations (deploy, remove, list, inspect). /// Implementations may use local docker CLI or SSH-based remote execution. /// public interface IDockerCliService { Task DeployStackAsync(string stackName, string composeYaml, bool resolveImage = false); Task RemoveStackAsync(string stackName); Task> ListStacksAsync(); Task> InspectStackServicesAsync(string stackName); /// Ensures a directory exists on the target host (equivalent to mkdir -p). Task EnsureDirectoryAsync(string path); /// /// Ensures the required folders exist on an NFS export, creating any that are missing. /// If is non-empty, creates it first as a subfolder of the export, /// then creates the volume folders inside it. /// Temporarily mounts the NFS export on the Docker host to create the directories. /// Task EnsureNfsFoldersAsync( string nfsServer, string nfsExport, IEnumerable folderNames, string? nfsExportFolder = null); /// /// Same as but returns the error message on failure /// so callers can surface actionable diagnostics. /// Task<(bool Success, string? Error)> EnsureNfsFoldersWithErrorAsync( string nfsServer, string nfsExport, IEnumerable folderNames, string? nfsExportFolder = null); /// /// Removes all Docker volumes whose names start with _. /// Volumes currently in use by running containers will be skipped. /// Safe for NFS volumes since data lives on the remote export, not in the local volume. /// Task RemoveStackVolumesAsync(string stackName); /// /// Lists all nodes in the Docker Swarm cluster. /// Must be executed against a Swarm manager node. /// Task> ListNodesAsync(); /// /// Force-updates a service so all its tasks are restarted and pick up any changed /// secrets or config (equivalent to docker service update --force). /// Task ForceUpdateServiceAsync(string serviceName); /// /// Opens a to a remote MySQL server through the /// implementation's transport (e.g. an SSH tunnel). The caller must dispose /// both the connection and the returned tunnel handle when finished. /// /// /// A tuple of (connection, tunnel). tunnel is /// and MUST be disposed after the connection is closed. /// Task<(MySqlConnection Connection, IDisposable Tunnel)> OpenMySqlConnectionAsync( string mysqlHost, int port, string adminUser, string adminPassword); /// /// Executes ALTER USER … IDENTIFIED BY … on a remote MySQL server via /// . /// Task<(bool Success, string Error)> AlterMySqlUserPasswordAsync( string mysqlHost, int port, string adminUser, string adminPassword, string targetUser, string newPassword); /// /// Atomically swaps one secret reference on a running service: /// removes and adds , /// preserving the in-container path as (defaults to /// when null, keeping the same /run/secrets/ filename). /// Task ServiceSwapSecretAsync(string serviceName, string oldSecretName, string newSecretName, string? targetAlias = null); } public class StackInfo { public string Name { get; set; } = string.Empty; public int ServiceCount { get; set; } } public class ServiceInfo { public string Name { get; set; } = string.Empty; public string Image { get; set; } = string.Empty; public string Replicas { get; set; } = string.Empty; }