diff --git a/MoonlightServers.Daemon/Configuration/AppConfiguration.cs b/MoonlightServers.Daemon/Configuration/AppConfiguration.cs index 5273cf9..6c09d5b 100644 --- a/MoonlightServers.Daemon/Configuration/AppConfiguration.cs +++ b/MoonlightServers.Daemon/Configuration/AppConfiguration.cs @@ -18,6 +18,15 @@ public class AppConfiguration public class DockerData { public string Uri { get; set; } = "unix:///var/run/docker.sock"; + public DockerCredentialData[] Credentials { get; set; } = []; + + public class DockerCredentialData + { + public string Domain { get; set; } + public string Username { get; set; } + public string Password { get; set; } + public string Email { get; set; } + } } public class SecurityData diff --git a/MoonlightServers.Daemon/Services/DockerImageService.cs b/MoonlightServers.Daemon/Services/DockerImageService.cs index 46b95e0..4519313 100644 --- a/MoonlightServers.Daemon/Services/DockerImageService.cs +++ b/MoonlightServers.Daemon/Services/DockerImageService.cs @@ -1,6 +1,7 @@ using Docker.DotNet; using Docker.DotNet.Models; using MoonCore.Attributes; +using MoonlightServers.Daemon.Configuration; namespace MoonlightServers.Daemon.Services; @@ -8,33 +9,69 @@ namespace MoonlightServers.Daemon.Services; public class DockerImageService { private readonly DockerClient DockerClient; + private readonly AppConfiguration Configuration; private readonly ILogger Logger; - public DockerImageService(DockerClient dockerClient, ILogger logger) + public DockerImageService( + DockerClient dockerClient, + ILogger logger, + AppConfiguration configuration + ) { + Configuration = configuration; DockerClient = dockerClient; Logger = logger; } public async Task Ensure(string name, Action? onProgressUpdated) { + // Figure out if and which credentials to use by checking for the domain + AuthConfig credentials = new(); + + var domain = GetDomainFromDockerImageName(name); + + var configuredCredentials = Configuration.Docker.Credentials + .FirstOrDefault(x => x.Domain.Equals(domain, StringComparison.InvariantCultureIgnoreCase)); + + if (configuredCredentials != null) + { + credentials.Username = configuredCredentials.Username; + credentials.Password = configuredCredentials.Password; + credentials.Email = configuredCredentials.Email; + } + + // Now we want to pull the image await DockerClient.Images.CreateImageAsync(new() { FromImage = name }, - new AuthConfig(), // TODO: Config for custom registries + credentials, new Progress(async message => { if (message.Progress == null) return; var line = $"[{message.ID}] {message.ProgressMessage}"; - + Logger.LogInformation("{line}", line); - - if(onProgressUpdated != null) + + if (onProgressUpdated != null) onProgressUpdated.Invoke(line); }) ); } + + private string GetDomainFromDockerImageName(string name) // Method names are my passion ;) + { + var nameParts = name.Split("/"); + + // If it has 1 part -> just the image name (e.g., "ubuntu") + // If it has 2 parts -> usually "user/image" (e.g., "library/ubuntu") + // If it has 3 or more -> assume first part is the registry domain + + if (nameParts.Length >= 3 || (nameParts.Length >= 2 && nameParts[0].Contains('.') || nameParts[0].Contains(':'))) + return nameParts[0]; // Registry domain is explicitly specified + + return "docker.io"; // Default Docker registry + } } \ No newline at end of file