- Create MigrationTool console app for exporting DB config to K8s YAML - Support dry-run mode and validation - Add Npgsql and YamlDotNet dependencies
213 lines
5.7 KiB
C#
213 lines
5.7 KiB
C#
using System.Text.Json;
|
|
|
|
namespace MigrationTool.Models;
|
|
|
|
/// <summary>
|
|
/// 网关租户路由数据库模型
|
|
/// </summary>
|
|
public class GwTenantRouteModel
|
|
{
|
|
public long Id { get; set; }
|
|
public string TenantCode { get; set; } = string.Empty;
|
|
public string ServiceName { get; set; } = string.Empty;
|
|
public string ClusterId { get; set; } = string.Empty;
|
|
public string PathPattern { get; set; } = string.Empty;
|
|
public string? MatchJson { get; set; }
|
|
public int Priority { get; set; }
|
|
public int Status { get; set; }
|
|
public bool IsGlobal { get; set; }
|
|
public bool IsDeleted { get; set; }
|
|
|
|
/// <summary>
|
|
/// 解析 Match JSON 获取路径
|
|
/// </summary>
|
|
public string GetPath()
|
|
{
|
|
if (string.IsNullOrEmpty(MatchJson))
|
|
return PathPattern;
|
|
|
|
try
|
|
{
|
|
var match = JsonSerializer.Deserialize<RouteMatchJson>(MatchJson);
|
|
return match?.Path ?? PathPattern;
|
|
}
|
|
catch
|
|
{
|
|
return PathPattern;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 解析 Match JSON 获取 Host
|
|
/// </summary>
|
|
public string? GetHost()
|
|
{
|
|
if (string.IsNullOrEmpty(MatchJson))
|
|
return null;
|
|
|
|
try
|
|
{
|
|
var match = JsonSerializer.Deserialize<RouteMatchJson>(MatchJson);
|
|
return match?.Hosts?.FirstOrDefault();
|
|
}
|
|
catch
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 路由匹配 JSON 结构
|
|
/// </summary>
|
|
public class RouteMatchJson
|
|
{
|
|
public string? Path { get; set; }
|
|
public List<string>? Methods { get; set; }
|
|
public List<string>? Hosts { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 网关集群数据库模型
|
|
/// </summary>
|
|
public class GwClusterModel
|
|
{
|
|
public string Id { get; set; } = string.Empty;
|
|
public string ClusterId { get; set; } = string.Empty;
|
|
public string Name { get; set; } = string.Empty;
|
|
public string? Description { get; set; }
|
|
public string? DestinationsJson { get; set; }
|
|
public int Status { get; set; }
|
|
public bool IsDeleted { get; set; }
|
|
|
|
/// <summary>
|
|
/// 解析 Destinations JSON
|
|
/// </summary>
|
|
public List<GwDestinationModel> GetDestinations()
|
|
{
|
|
if (string.IsNullOrEmpty(DestinationsJson))
|
|
return [];
|
|
|
|
try
|
|
{
|
|
var destinations = JsonSerializer.Deserialize<List<GwDestinationModel>>(DestinationsJson);
|
|
return destinations ?? [];
|
|
}
|
|
catch
|
|
{
|
|
return [];
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 目标端点模型
|
|
/// </summary>
|
|
public class GwDestinationModel
|
|
{
|
|
public string DestinationId { get; set; } = string.Empty;
|
|
public string Address { get; set; } = string.Empty;
|
|
public string? Health { get; set; }
|
|
public int Weight { get; set; } = 1;
|
|
public int HealthStatus { get; set; } = 1;
|
|
public int Status { get; set; } = 1;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 迁移结果报告
|
|
/// </summary>
|
|
public class MigrationReport
|
|
{
|
|
public DateTime StartTime { get; set; }
|
|
public DateTime EndTime { get; set; }
|
|
public int TotalRoutes { get; set; }
|
|
public int SuccessCount { get; set; }
|
|
public int FailedCount { get; set; }
|
|
public int SkippedCount { get; set; }
|
|
public List<MigrationEntry> Entries { get; set; } = [];
|
|
public TimeSpan Duration => EndTime - StartTime;
|
|
|
|
public void PrintSummary()
|
|
{
|
|
Console.WriteLine();
|
|
Console.WriteLine("=".PadRight(60, '='));
|
|
Console.WriteLine("迁移报告");
|
|
Console.WriteLine("=".PadRight(60, '='));
|
|
Console.WriteLine($"开始时间: {StartTime:yyyy-MM-dd HH:mm:ss}");
|
|
Console.WriteLine($"结束时间: {EndTime:yyyy-MM-dd HH:mm:ss}");
|
|
Console.WriteLine($"总耗时: {Duration.TotalSeconds:F2} 秒");
|
|
Console.WriteLine("-".PadRight(60, '-'));
|
|
Console.WriteLine($"总路由数: {TotalRoutes}");
|
|
Console.WriteLine($"成功: {SuccessCount}");
|
|
Console.WriteLine($"失败: {FailedCount}");
|
|
Console.WriteLine($"跳过: {SkippedCount}");
|
|
Console.WriteLine("=".PadRight(60, '='));
|
|
|
|
if (FailedCount > 0)
|
|
{
|
|
Console.WriteLine();
|
|
Console.WriteLine("失败详情:");
|
|
foreach (var entry in Entries.Where(e => e.Status == MigrationStatus.Failed))
|
|
{
|
|
Console.WriteLine($" - {entry.ServiceName}: {entry.ErrorMessage}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 迁移条目
|
|
/// </summary>
|
|
public class MigrationEntry
|
|
{
|
|
public string ServiceName { get; set; } = string.Empty;
|
|
public string TenantCode { get; set; } = string.Empty;
|
|
public string ClusterId { get; set; } = string.Empty;
|
|
public string OutputPath { get; set; } = string.Empty;
|
|
public MigrationStatus Status { get; set; }
|
|
public string? ErrorMessage { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 迁移状态
|
|
/// </summary>
|
|
public enum MigrationStatus
|
|
{
|
|
Success,
|
|
Failed,
|
|
Skipped
|
|
}
|
|
|
|
/// <summary>
|
|
/// K8s Service YAML 模型
|
|
/// </summary>
|
|
public class K8sServiceModel
|
|
{
|
|
public string ApiVersion { get; set; } = "v1";
|
|
public string Kind { get; set; } = "Service";
|
|
public K8sMetadata Metadata { get; set; } = new();
|
|
public K8sSpec Spec { get; set; } = new();
|
|
}
|
|
|
|
public class K8sMetadata
|
|
{
|
|
public string Name { get; set; } = string.Empty;
|
|
public Dictionary<string, string> Labels { get; set; } = new();
|
|
public Dictionary<string, string>? Annotations { get; set; }
|
|
}
|
|
|
|
public class K8sSpec
|
|
{
|
|
public string Type { get; set; } = "ClusterIP";
|
|
public Dictionary<string, string> Selector { get; set; } = new();
|
|
public List<K8sPort> Ports { get; set; } = [];
|
|
}
|
|
|
|
public class K8sPort
|
|
{
|
|
public int Port { get; set; }
|
|
public int TargetPort { get; set; }
|
|
public string? Name { get; set; }
|
|
public string? Protocol { get; set; }
|
|
}
|