| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- using System.Text;
- using RackPeek.Domain.Persistence;
- using RackPeek.Domain.Resources;
- using RackPeek.Domain.Resources.SystemResources;
- namespace RackPeek.Domain.UseCases.Hosts;
- public sealed record HostsExportOptions {
- /// <summary>
- /// Only include resources that have at least one of these tags.
- /// </summary>
- public IReadOnlyList<string> IncludeTags { get; init; } = [];
- /// <summary>
- /// If true, append domain suffix (e.g. .home.local)
- /// </summary>
- public string? DomainSuffix { get; init; }
- /// <summary>
- /// If true, include localhost defaults at top.
- /// </summary>
- public bool IncludeLocalhostDefaults { get; init; } = true;
- }
- public sealed record HostsExportResult(
- string HostsText,
- IReadOnlyList<string> Warnings);
- public static class HostsFileGenerator {
- public static HostsExportResult ToHostsFile(
- this IReadOnlyList<Resource> resources,
- HostsExportOptions? options = null) {
- options ??= new HostsExportOptions();
- var sb = new StringBuilder();
- var warnings = new List<string>();
- if (options.IncludeLocalhostDefaults) {
- sb.AppendLine("127.0.0.1 localhost");
- sb.AppendLine("::1 localhost");
- sb.AppendLine();
- }
- foreach (Resource r in resources.OrderBy(x => x.Name)) {
- if (options.IncludeTags.Any()) {
- var tags = r.Tags ?? [];
- if (!options.IncludeTags.Any(t =>
- tags.Contains(t, StringComparer.OrdinalIgnoreCase)))
- continue;
- }
- var address = GetAddress(r);
- if (string.IsNullOrWhiteSpace(address)) continue;
- var hostName = SanitizeHostName(r.Name);
- if (!string.IsNullOrWhiteSpace(options.DomainSuffix))
- hostName = $"{hostName}.{options.DomainSuffix.Trim('.')}";
- sb.AppendLine($"{address} {hostName}");
- }
- if (sb.Length == 0)
- warnings.Add("No host entries generated.");
- return new HostsExportResult(sb.ToString().TrimEnd(), warnings);
- }
- private static string? GetAddress(Resource r) {
- if (r is SystemResource { Ip: not null } system &&
- !string.IsNullOrWhiteSpace(system!.Ip)) {
- return system.Ip;
- }
- if (r.Labels.TryGetValue("ip", out var ip) && !string.IsNullOrWhiteSpace(ip))
- return ip;
- if (r.Labels.TryGetValue("hostname", out var hn) && !string.IsNullOrWhiteSpace(hn))
- return hn;
- if (r.Labels.TryGetValue("ansible_host", out var ah) && !string.IsNullOrWhiteSpace(ah))
- return ah;
- return null;
- }
- private static string SanitizeHostName(string name) {
- var sb = new StringBuilder();
- foreach (var ch in name.Trim().ToLowerInvariant())
- if (char.IsLetterOrDigit(ch) || ch == '-')
- sb.Append(ch);
- else if (ch == '_' || ch == ' ')
- sb.Append('-');
- return sb.Length == 0 ? "host" : sb.ToString();
- }
- }
- public class HostsFileExportUseCase(IResourceCollection repository) : IUseCase {
- public async Task<HostsExportResult?> ExecuteAsync(HostsExportOptions options) {
- IReadOnlyList<Resource> resources = await repository.GetAllOfTypeAsync<Resource>();
- return resources.ToHostsFile(options);
- }
- }
|