SshConfigGenerator.cs 3.2 KB

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