SshConfigGenerator.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System.Text;
  2. using RackPeek.Domain.Resources;
  3. using RackPeek.Domain.Resources.SystemResources;
  4. namespace RackPeek.Domain.UseCases.SSH;
  5. public static class SshConfigGenerator {
  6. public static SshExportResult ToSshConfig(
  7. this IReadOnlyList<Resource> resources,
  8. SshExportOptions? options = null) {
  9. options ??= new SshExportOptions();
  10. var sb = new StringBuilder();
  11. var warnings = new List<string>();
  12. foreach (Resource r in resources.OrderBy(x => x.Name)) {
  13. if (options.IncludeTags.Any()) {
  14. var tags = r.Tags ?? [];
  15. if (!options.IncludeTags.Any(t =>
  16. tags.Contains(t, StringComparer.OrdinalIgnoreCase)))
  17. continue;
  18. }
  19. var address = GetAddress(r);
  20. if (string.IsNullOrWhiteSpace(address)) continue;
  21. var alias = options.UseResourceNameAsAlias
  22. ? SanitizeAlias(r.Name)
  23. : address;
  24. var user = GetLabel(r, "ssh_user")
  25. ?? GetLabel(r, "ansible_user")
  26. ?? options.DefaultUser;
  27. var port = GetPort(r) ?? options.DefaultPort;
  28. var identity = GetLabel(r, "ssh_identity_file")
  29. ?? options.DefaultIdentityFile;
  30. sb.AppendLine($"Host {alias}");
  31. sb.AppendLine($" HostName {address}");
  32. if (!string.IsNullOrWhiteSpace(user))
  33. sb.AppendLine($" User {user}");
  34. if (port != 22)
  35. sb.AppendLine($" Port {port}");
  36. if (!string.IsNullOrWhiteSpace(identity))
  37. sb.AppendLine($" IdentityFile {identity}");
  38. sb.AppendLine();
  39. }
  40. if (sb.Length == 0)
  41. warnings.Add("No SSH entries generated.");
  42. return new SshExportResult(sb.ToString().TrimEnd(), warnings);
  43. }
  44. private static string? GetAddress(Resource r) {
  45. if (r is SystemResource { Ip: not null } system &&
  46. !string.IsNullOrWhiteSpace(system!.Ip)) {
  47. return system.Ip;
  48. }
  49. if (r.Labels.TryGetValue("ip", out var ip) && !string.IsNullOrWhiteSpace(ip))
  50. return ip;
  51. if (r.Labels.TryGetValue("hostname", out var hn) && !string.IsNullOrWhiteSpace(hn))
  52. return hn;
  53. if (r.Labels.TryGetValue("ansible_host", out var ah) && !string.IsNullOrWhiteSpace(ah))
  54. return ah;
  55. return null;
  56. }
  57. private static string? GetLabel(Resource r, string key) {
  58. if (r.Labels.TryGetValue(key, out var val) &&
  59. !string.IsNullOrWhiteSpace(val))
  60. return val;
  61. return null;
  62. }
  63. private static int? GetPort(Resource r) {
  64. if (r.Labels.TryGetValue("ssh_port", out var portStr) &&
  65. int.TryParse(portStr, out var port))
  66. return port;
  67. if (r.Labels.TryGetValue("ansible_port", out var ansiblePort) &&
  68. int.TryParse(ansiblePort, out var aPort))
  69. return aPort;
  70. return null;
  71. }
  72. private static string SanitizeAlias(string name) {
  73. var sb = new StringBuilder();
  74. foreach (var ch in name.Trim().ToLowerInvariant())
  75. if (char.IsLetterOrDigit(ch) || ch == '_' || ch == '-')
  76. sb.Append(ch);
  77. else if (ch == '.' || ch == ' ')
  78. sb.Append('-');
  79. return sb.Length == 0 ? "host" : sb.ToString();
  80. }
  81. }