feat: внедрение RazorConsole TUI с runtime-управлением MCP-инструментами
- Добавлен RazorConsole.Core для интерактивного TUI-дашборда - ToolRegistryService: живое включение/отключение модулей и отдельных методов - InMemoryLogSink: кольцевой буфер логов с фильтрацией по модулю - TUI: 3 таба (Overview, Logs, Settings) - IToolModule: generic-интерфейс для легкого добавления новых MCP-модулей - Guard-проверка TryCheckEnabled() во всех существующих инструментах
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
using System.ComponentModel;
|
||||
using k8s;
|
||||
using k8s.Autorest;
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sConfigTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
public sealed class K8sConfigTools(
|
||||
K8sClientProvider clientProvider,
|
||||
IConfiguration configuration,
|
||||
ToolRegistryService registry,
|
||||
ILogger<K8sConfigTools>? logger = null)
|
||||
: KubernetesToolsBase(clientProvider, configuration, registry, logger)
|
||||
{
|
||||
private const int MaxSecretKeyLimit = 100;
|
||||
|
||||
@@ -15,6 +21,8 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListConfigMaps", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
@@ -52,6 +60,8 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetConfigMapData", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
@@ -83,6 +93,8 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListSecrets", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
@@ -120,6 +132,8 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetSecretKeys", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
|
||||
@@ -3,12 +3,18 @@ using System.Text.Json;
|
||||
using k8s;
|
||||
using k8s.Autorest;
|
||||
using k8s.Models;
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sDeploymentTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
public sealed class K8sDeploymentTools(
|
||||
K8sClientProvider clientProvider,
|
||||
IConfiguration configuration,
|
||||
ToolRegistryService registry,
|
||||
ILogger<K8sDeploymentTools>? logger = null)
|
||||
: KubernetesToolsBase(clientProvider, configuration, registry, logger)
|
||||
{
|
||||
private const int MinReplicas = 0;
|
||||
private const int MaxReplicas = 100;
|
||||
@@ -18,6 +24,8 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListDeployments", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
@@ -58,6 +66,8 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ScaleDeployment", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
|
||||
@@ -95,6 +105,8 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetRolloutStatus", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
@@ -126,6 +138,8 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("RestartDeployment", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
using System.ComponentModel;
|
||||
using k8s;
|
||||
using k8s.Autorest;
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sNetworkTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
public sealed class K8sNetworkTools(
|
||||
K8sClientProvider clientProvider,
|
||||
IConfiguration configuration,
|
||||
ToolRegistryService registry,
|
||||
ILogger<K8sNetworkTools>? logger = null)
|
||||
: KubernetesToolsBase(clientProvider, configuration, registry, logger)
|
||||
{
|
||||
[McpServerTool, Description("Список service в namespace")]
|
||||
public async Task<string> ListServices(
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListServices", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
@@ -55,6 +63,8 @@ public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfigura
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetServiceDetails", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
@@ -90,6 +100,8 @@ public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfigura
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListIngresses", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
using System.ComponentModel;
|
||||
using k8s;
|
||||
using k8s.Autorest;
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sPodsTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
public sealed class K8sPodsTools(
|
||||
K8sClientProvider clientProvider,
|
||||
IConfiguration configuration,
|
||||
ToolRegistryService registry,
|
||||
ILogger<K8sPodsTools>? logger = null)
|
||||
: KubernetesToolsBase(clientProvider, configuration, registry, logger)
|
||||
{
|
||||
private const int MaxTailLines = 10;
|
||||
private const int MinTailLines = 10;
|
||||
@@ -16,6 +22,8 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("ListPods", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
@@ -55,6 +63,8 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetPodStatus", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
@@ -90,6 +100,8 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
int? tailLines = 100,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
if (!TryCheckEnabled("GetPodLogs", out var enabledError)) return enabledError;
|
||||
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
|
||||
|
||||
31
LazyBear.MCP/Services/Kubernetes/KubernetesToolModule.cs
Normal file
31
LazyBear.MCP/Services/Kubernetes/KubernetesToolModule.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
public sealed class KubernetesToolModule : IToolModule
|
||||
{
|
||||
public string ModuleName => "Kubernetes";
|
||||
public string Description => "Kubernetes: поды, деплойменты, сервисы, конфиги";
|
||||
|
||||
public IReadOnlyList<string> ToolNames =>
|
||||
[
|
||||
// Pods
|
||||
"ListPods",
|
||||
"GetPodStatus",
|
||||
"GetPodLogs",
|
||||
// Deployments
|
||||
"ListDeployments",
|
||||
"ScaleDeployment",
|
||||
"GetRolloutStatus",
|
||||
"RestartDeployment",
|
||||
// Network
|
||||
"ListServices",
|
||||
"GetServiceDetails",
|
||||
"ListIngresses",
|
||||
// Config
|
||||
"ListConfigMaps",
|
||||
"GetConfigMapData",
|
||||
"ListSecrets",
|
||||
"GetSecretKeys"
|
||||
];
|
||||
}
|
||||
@@ -1,18 +1,36 @@
|
||||
using System.ComponentModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using k8s;
|
||||
using LazyBear.MCP.Services.ToolRegistry;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public abstract class KubernetesToolsBase(K8sClientProvider clientProvider, IConfiguration configuration, ILogger? logger = null)
|
||||
public abstract class KubernetesToolsBase(
|
||||
K8sClientProvider clientProvider,
|
||||
IConfiguration configuration,
|
||||
ToolRegistryService registry,
|
||||
ILogger? logger = null)
|
||||
{
|
||||
protected readonly IKubernetes? _client = clientProvider.Client;
|
||||
protected readonly string? _clientInitializationError = clientProvider.InitializationError;
|
||||
protected readonly string _defaultNamespace = configuration["Kubernetes:DefaultNamespace"] ?? "default";
|
||||
protected readonly ILogger? _logger = logger;
|
||||
protected readonly ToolRegistryService _registry = registry;
|
||||
|
||||
protected const string K8sModuleName = "Kubernetes";
|
||||
|
||||
protected bool TryCheckEnabled(string toolName, out string error)
|
||||
{
|
||||
if (!_registry.IsToolEnabled(K8sModuleName, toolName))
|
||||
{
|
||||
error = $"Инструмент '{toolName}' модуля Kubernetes отключён в TUI.";
|
||||
return false;
|
||||
}
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static readonly Regex NamespaceRegex = new(@"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
|
||||
protected static readonly Regex ResourceNameRegex = new(@"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$", RegexOptions.Compiled, TimeSpan.FromSeconds(1));
|
||||
|
||||
Reference in New Issue
Block a user