Add Kubernetes and Jira MCP tools with auto-registration
This commit is contained in:
@@ -6,17 +6,16 @@ using ModelContextProtocol.Server;
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfiguration configuration)
|
||||
public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sConfigTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
{
|
||||
private readonly IKubernetes? _client = clientProvider.Client;
|
||||
private readonly string? _clientInitializationError = clientProvider.InitializationError;
|
||||
private readonly string _defaultNamespace = configuration["Kubernetes:DefaultNamespace"] ?? "default";
|
||||
private const int MaxSecretKeyLimit = 100;
|
||||
|
||||
[McpServerTool, Description("Список ConfigMap в namespace")]
|
||||
public async Task<string> ListConfigMaps(
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -53,6 +52,8 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -82,6 +83,7 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -118,6 +120,8 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -157,49 +161,4 @@ public sealed class K8sConfigTools(K8sClientProvider clientProvider, IConfigurat
|
||||
return FormatError("get_secret_keys", ns, ex, name);
|
||||
}
|
||||
}
|
||||
|
||||
private string ResolveNamespace(string? @namespace)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(@namespace) ? _defaultNamespace : @namespace;
|
||||
}
|
||||
|
||||
private static string BuildClientInitializationError()
|
||||
{
|
||||
return "Kubernetes клиент не инициализирован. Проверьте Kubernetes:KubeconfigPath или in-cluster окружение (KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT).";
|
||||
}
|
||||
|
||||
private bool TryGetClient(out IKubernetes client, out string error)
|
||||
{
|
||||
if (_client is null)
|
||||
{
|
||||
client = null!;
|
||||
var details = string.IsNullOrWhiteSpace(_clientInitializationError)
|
||||
? string.Empty
|
||||
: $" Детали: {_clientInitializationError}";
|
||||
error = BuildClientInitializationError() + details;
|
||||
return false;
|
||||
}
|
||||
|
||||
client = _client;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string FormatError(string toolName, string @namespace, Exception exception, string? resourceName = null)
|
||||
{
|
||||
var resourcePart = string.IsNullOrWhiteSpace(resourceName) ? string.Empty : $", resource='{resourceName}'";
|
||||
|
||||
if (exception is HttpOperationException httpException)
|
||||
{
|
||||
var statusCode = httpException.Response?.StatusCode;
|
||||
var reason = httpException.Response?.ReasonPhrase;
|
||||
var body = string.IsNullOrWhiteSpace(httpException.Response?.Content)
|
||||
? "-"
|
||||
: httpException.Response!.Content;
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): status={(int?)statusCode ?? 0} {reason}, details={body}";
|
||||
}
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): {exception.GetType().Name}: {exception.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,17 +8,17 @@ using ModelContextProtocol.Server;
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfiguration configuration)
|
||||
public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sDeploymentTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
{
|
||||
private readonly IKubernetes? _client = clientProvider.Client;
|
||||
private readonly string? _clientInitializationError = clientProvider.InitializationError;
|
||||
private readonly string _defaultNamespace = configuration["Kubernetes:DefaultNamespace"] ?? "default";
|
||||
private const int MinReplicas = 0;
|
||||
private const int MaxReplicas = 100;
|
||||
|
||||
[McpServerTool, Description("Список deployment в namespace")]
|
||||
public async Task<string> ListDeployments(
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -58,6 +58,14 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
|
||||
if (replicas < MinReplicas || replicas > MaxReplicas)
|
||||
{
|
||||
return $"Invalid replicas value: {replicas}. Must be between {MinReplicas} and {MaxReplicas}.";
|
||||
}
|
||||
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -87,6 +95,8 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -116,6 +126,8 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -151,49 +163,4 @@ public sealed class K8sDeploymentTools(K8sClientProvider clientProvider, IConfig
|
||||
return FormatError("restart_deployment", ns, ex, name);
|
||||
}
|
||||
}
|
||||
|
||||
private string ResolveNamespace(string? @namespace)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(@namespace) ? _defaultNamespace : @namespace;
|
||||
}
|
||||
|
||||
private static string BuildClientInitializationError()
|
||||
{
|
||||
return "Kubernetes клиент не инициализирован. Проверьте Kubernetes:KubeconfigPath или in-cluster окружение (KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT).";
|
||||
}
|
||||
|
||||
private bool TryGetClient(out IKubernetes client, out string error)
|
||||
{
|
||||
if (_client is null)
|
||||
{
|
||||
client = null!;
|
||||
var details = string.IsNullOrWhiteSpace(_clientInitializationError)
|
||||
? string.Empty
|
||||
: $" Детали: {_clientInitializationError}";
|
||||
error = BuildClientInitializationError() + details;
|
||||
return false;
|
||||
}
|
||||
|
||||
client = _client;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string FormatError(string toolName, string @namespace, Exception exception, string? resourceName = null)
|
||||
{
|
||||
var resourcePart = string.IsNullOrWhiteSpace(resourceName) ? string.Empty : $", resource='{resourceName}'";
|
||||
|
||||
if (exception is HttpOperationException httpException)
|
||||
{
|
||||
var statusCode = httpException.Response?.StatusCode;
|
||||
var reason = httpException.Response?.ReasonPhrase;
|
||||
var body = string.IsNullOrWhiteSpace(httpException.Response?.Content)
|
||||
? "-"
|
||||
: httpException.Response!.Content;
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): status={(int?)statusCode ?? 0} {reason}, details={body}";
|
||||
}
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): {exception.GetType().Name}: {exception.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,14 @@ using ModelContextProtocol.Server;
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfiguration configuration)
|
||||
public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sNetworkTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
{
|
||||
private readonly IKubernetes? _client = clientProvider.Client;
|
||||
private readonly string? _clientInitializationError = clientProvider.InitializationError;
|
||||
private readonly string _defaultNamespace = configuration["Kubernetes:DefaultNamespace"] ?? "default";
|
||||
|
||||
[McpServerTool, Description("Список service в namespace")]
|
||||
public async Task<string> ListServices(
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -58,6 +55,8 @@ public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfigura
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -91,6 +90,7 @@ public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfigura
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -136,49 +136,4 @@ public sealed class K8sNetworkTools(K8sClientProvider clientProvider, IConfigura
|
||||
return FormatError("list_ingresses", ns, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private string ResolveNamespace(string? @namespace)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(@namespace) ? _defaultNamespace : @namespace;
|
||||
}
|
||||
|
||||
private static string BuildClientInitializationError()
|
||||
{
|
||||
return "Kubernetes клиент не инициализирован. Проверьте Kubernetes:KubeconfigPath или in-cluster окружение (KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT).";
|
||||
}
|
||||
|
||||
private bool TryGetClient(out IKubernetes client, out string error)
|
||||
{
|
||||
if (_client is null)
|
||||
{
|
||||
client = null!;
|
||||
var details = string.IsNullOrWhiteSpace(_clientInitializationError)
|
||||
? string.Empty
|
||||
: $" Детали: {_clientInitializationError}";
|
||||
error = BuildClientInitializationError() + details;
|
||||
return false;
|
||||
}
|
||||
|
||||
client = _client;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string FormatError(string toolName, string @namespace, Exception exception, string? resourceName = null)
|
||||
{
|
||||
var resourcePart = string.IsNullOrWhiteSpace(resourceName) ? string.Empty : $", resource='{resourceName}'";
|
||||
|
||||
if (exception is HttpOperationException httpException)
|
||||
{
|
||||
var statusCode = httpException.Response?.StatusCode;
|
||||
var reason = httpException.Response?.ReasonPhrase;
|
||||
var body = string.IsNullOrWhiteSpace(httpException.Response?.Content)
|
||||
? "-"
|
||||
: httpException.Response!.Content;
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): status={(int?)statusCode ?? 0} {reason}, details={body}";
|
||||
}
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): {exception.GetType().Name}: {exception.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,17 @@ using ModelContextProtocol.Server;
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguration configuration)
|
||||
public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguration configuration, ILogger<K8sPodsTools>? logger = null) : KubernetesToolsBase(clientProvider, configuration, logger)
|
||||
{
|
||||
private readonly IKubernetes? _client = clientProvider.Client;
|
||||
private readonly string? _clientInitializationError = clientProvider.InitializationError;
|
||||
private readonly string _defaultNamespace = configuration["Kubernetes:DefaultNamespace"] ?? "default";
|
||||
private const int MaxTailLines = 10;
|
||||
private const int MinTailLines = 10;
|
||||
|
||||
[McpServerTool, Description("Список подов в namespace")]
|
||||
public async Task<string> ListPods(
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -55,6 +55,8 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
[Description("Namespace Kubernetes")] string? @namespace = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -88,6 +90,18 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
int? tailLines = 100,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ValidateResourceName(name, nameof(name));
|
||||
ValidateNamespace(@namespace ?? _defaultNamespace, nameof(@namespace));
|
||||
|
||||
if (tailLines < MinTailLines)
|
||||
{
|
||||
tailLines = MinTailLines;
|
||||
}
|
||||
if (tailLines > MaxTailLines)
|
||||
{
|
||||
tailLines = MaxTailLines;
|
||||
}
|
||||
|
||||
var ns = ResolveNamespace(@namespace);
|
||||
if (!TryGetClient(out var client, out var clientError))
|
||||
{
|
||||
@@ -100,7 +114,7 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
name,
|
||||
ns,
|
||||
container: container,
|
||||
tailLines: tailLines,
|
||||
tailLines: (int?)tailLines,
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
using var reader = new StreamReader(logStream);
|
||||
@@ -118,49 +132,4 @@ public sealed class K8sPodsTools(K8sClientProvider clientProvider, IConfiguratio
|
||||
return FormatError("get_pod_logs", ns, ex, name);
|
||||
}
|
||||
}
|
||||
|
||||
private string ResolveNamespace(string? @namespace)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(@namespace) ? _defaultNamespace : @namespace;
|
||||
}
|
||||
|
||||
private static string BuildClientInitializationError()
|
||||
{
|
||||
return "Kubernetes клиент не инициализирован. Проверьте Kubernetes:KubeconfigPath или in-cluster окружение (KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT).";
|
||||
}
|
||||
|
||||
private bool TryGetClient(out IKubernetes client, out string error)
|
||||
{
|
||||
if (_client is null)
|
||||
{
|
||||
client = null!;
|
||||
var details = string.IsNullOrWhiteSpace(_clientInitializationError)
|
||||
? string.Empty
|
||||
: $" Детали: {_clientInitializationError}";
|
||||
error = BuildClientInitializationError() + details;
|
||||
return false;
|
||||
}
|
||||
|
||||
client = _client;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static string FormatError(string toolName, string @namespace, Exception exception, string? resourceName = null)
|
||||
{
|
||||
var resourcePart = string.IsNullOrWhiteSpace(resourceName) ? string.Empty : $", resource='{resourceName}'";
|
||||
|
||||
if (exception is HttpOperationException httpException)
|
||||
{
|
||||
var statusCode = httpException.Response?.StatusCode;
|
||||
var reason = httpException.Response?.ReasonPhrase;
|
||||
var body = string.IsNullOrWhiteSpace(httpException.Response?.Content)
|
||||
? "-"
|
||||
: httpException.Response!.Content;
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): status={(int?)statusCode ?? 0} {reason}, details={body}";
|
||||
}
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): {exception.GetType().Name}: {exception.Message}";
|
||||
}
|
||||
}
|
||||
|
||||
107
LazyBear.MCP/Services/Kubernetes/KubernetesToolsBase.cs
Normal file
107
LazyBear.MCP/Services/Kubernetes/KubernetesToolsBase.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System.ComponentModel;
|
||||
using System.Text.RegularExpressions;
|
||||
using k8s;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ModelContextProtocol.Server;
|
||||
|
||||
namespace LazyBear.MCP.Services.Kubernetes;
|
||||
|
||||
[McpServerToolType]
|
||||
public abstract class KubernetesToolsBase(K8sClientProvider clientProvider, IConfiguration configuration, 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 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));
|
||||
|
||||
protected string ResolveNamespace(string? @namespace)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(@namespace) ? _defaultNamespace : @namespace;
|
||||
}
|
||||
|
||||
protected void ValidateNamespace(string value, string parameterName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new ArgumentException($"Namespace не может быть пустым", parameterName);
|
||||
}
|
||||
if (value.Length > 63)
|
||||
{
|
||||
throw new ArgumentException($"Namespace не может быть длиннее 63 символов", parameterName);
|
||||
}
|
||||
if (!NamespaceRegex.IsMatch(value))
|
||||
{
|
||||
throw new ArgumentException($"Невалидный формат namespace: '{value}'. Только lowercase alphanumetic, -, не может начинаться/заканчиваться на -", parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ValidateResourceName(string value, string parameterName)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
throw new ArgumentException($"Resource name не может быть пустым", parameterName);
|
||||
}
|
||||
if (value.Length > 253)
|
||||
{
|
||||
throw new ArgumentException($"Resource name не может быть длиннее 253 символов", parameterName);
|
||||
}
|
||||
if (!ResourceNameRegex.IsMatch(value))
|
||||
{
|
||||
throw new ArgumentException($"Невалидный формат: '{value}'. Только lowercase alphanumetic, -, не может начинаться/заканчиваться на -", parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
protected bool TryGetClient(out IKubernetes client, out string error)
|
||||
{
|
||||
if (_client is null)
|
||||
{
|
||||
client = null!;
|
||||
var details = string.IsNullOrWhiteSpace(_clientInitializationError)
|
||||
? string.Empty
|
||||
: $" Детали: {_clientInitializationError}";
|
||||
error = "Kubernetes клиент не инициализирован. Проверьте Kubernetes:KubeconfigPath или in-cluster окружение (KUBERNETES_SERVICE_HOST/KUBERNETES_SERVICE_PORT)." + details;
|
||||
return false;
|
||||
}
|
||||
|
||||
client = _client;
|
||||
error = string.Empty;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected string FormatError(string toolName, string @namespace, Exception exception, string? resourceName = null)
|
||||
{
|
||||
_logger?.LogError(exception, "Ошибка Kubernetes в tool '{ToolName}' (namespace='{Namespace}'{ResourcePart}): {ExceptionMessage}",
|
||||
toolName, @namespace,
|
||||
string.IsNullOrWhiteSpace(resourceName) ? string.Empty : $", resource='{resourceName}'",
|
||||
exception.Message);
|
||||
|
||||
var resourcePart = string.IsNullOrWhiteSpace(resourceName) ? string.Empty : $", resource='{resourceName}'";
|
||||
|
||||
if (exception is global::k8s.Autorest.HttpOperationException httpException)
|
||||
{
|
||||
var statusCode = httpException.Response?.StatusCode;
|
||||
var reason = httpException.Response?.ReasonPhrase;
|
||||
var body = string.IsNullOrWhiteSpace(httpException.Response?.Content)
|
||||
? "-"
|
||||
: httpException.Response!.Content;
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): status={(int?)statusCode ?? 0} {reason}, details={body}";
|
||||
}
|
||||
|
||||
return $"Ошибка Kubernetes в tool '{toolName}' (namespace='{@namespace}'{resourcePart}): {exception.GetType().Name}: {exception.Message}";
|
||||
}
|
||||
|
||||
protected string FormatException(string toolName, Exception exception, string? resource = null)
|
||||
{
|
||||
_logger?.LogError(exception, "Ошибка exception в tool '{ToolName}'{ResourcePart}: {ExceptionMessage}",
|
||||
toolName,
|
||||
string.IsNullOrWhiteSpace(resource) ? string.Empty : $", resource='{resource}'",
|
||||
exception.Message);
|
||||
|
||||
var resourcePart = string.IsNullOrWhiteSpace(resource) ? string.Empty : $", resource='{resource}'";
|
||||
return $"Ошибка в tool '{toolName}'{resourcePart}: {exception.GetType().Name}: {exception.Message}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user