using System.Text.Json;
namespace SQLInsight.Core.Configuration;
///
/// What SQLInsight Web asks the agent to do (insight.AgentRequests). Connection tests and discovery run in the agent,
/// as the agent's identity, because that is what connects to the instances in production; the web UI only queues the
/// request and shows the result.
///
public static class AgentRequestKind
{
/// Connect to a configured instance and check the agent's rights there.
public const string ConnectionTest = "ConnectionTest";
/// List the databases on a configured instance (state, size, recovery model, Dynamics AX …).
public const string DatabaseDiscovery = "DatabaseDiscovery";
/// Find SQL Server instances on a computer (SQL Server Browser, and the registry on the agent's own computer).
public const string InstanceDiscovery = "InstanceDiscovery";
public static readonly IReadOnlyList All = [ConnectionTest, DatabaseDiscovery, InstanceDiscovery];
}
public static class AgentRequestStatus
{
public const string Pending = "Pending";
public const string Running = "Running";
public const string Done = "Done";
public const string Failed = "Failed";
}
/// JSON of request parameters and results, shared by the agent (writes) and the web UI and API (reads).
public static class AgentRequestJson
{
public static readonly JsonSerializerOptions Options = new(JsonSerializerDefaults.Web);
public static string Serialize(T value) => JsonSerializer.Serialize(value, Options);
public static T? Deserialize(string? json)
where T : class
{
if (string.IsNullOrWhiteSpace(json))
{
return null;
}
try
{
return JsonSerializer.Deserialize(json, Options);
}
catch (JsonException)
{
return null;
}
}
}
/// Parameters of an .
/// The computer to ask; empty for the agent's own computer.
public sealed record InstanceDiscoveryParameters(string? Host);
/// One right the agent needs (or may have) on an instance, and whether it has it.
/// The permission as written in GRANT, e.g. VIEW SERVER STATE, or SELECT ON msdb.dbo.backupset.
/// False for optional rights (ALTER TRACE): missing them limits a feature, not the monitoring.
/// What SQLInsight uses it for (Danish).
public sealed record PermissionStatus(string Name, bool Granted, bool Required, string Purpose);
/// The outcome of a connection test, as the agent saw it.
public sealed record ConnectionTestResult
{
public bool Connected { get; init; }
public string? Error { get; init; }
/// What to do about (Danish).
public string? Hint { get; init; }
public string? Provider { get; init; }
public bool UsedLegacyFallback { get; init; }
public string? ProductVersion { get; init; }
public string? Release { get; init; }
public string? Edition { get; init; }
public string? ServerName { get; init; }
/// The login the agent arrived as (SUSER_SNAME()): the one the GRANT script is for.
public string? Login { get; init; }
/// The agent is sysadmin on the instance. It works, but it is more than it needs.
public bool IsSysadmin { get; init; }
/// False on SQL Server 2000, which cannot report effective permissions (no HAS_PERMS_BY_NAME).
public bool PermissionsChecked { get; init; }
public IReadOnlyList Permissions { get; init; } = [];
/// Notes about the result, e.g. why permissions were not checked (Danish).
public IReadOnlyList Notes { get; init; } = [];
public IEnumerable MissingRequired => Permissions.Where(p => p.Required && !p.Granted);
}
/// A database as the agent found it on an instance.
public sealed record DiscoveredDatabase
{
public required string Name { get; init; }
public int DatabaseId { get; init; }
public string State { get; init; } = "ONLINE";
public long? SizeMb { get; init; }
public string? RecoveryModel { get; init; }
public int? CompatibilityLevel { get; init; }
public bool IsReadOnly { get; init; }
public bool IsSystem { get; init; }
/// A database snapshot (not monitored on its own).
public bool IsSnapshot { get; init; }
/// The agent can enter the database (HAS_DBACCESS); without it, database-specific checks cannot run there.
public bool HasAccess { get; init; }
/// Recognised as Dynamics AX by the central detection (Core/DynamicsAx/AxDetection.cs).
public bool IsDynamicsAx { get; init; }
/// The AX version as ("3.0", "2009", "2012 R2/R3" …), when .
public string? DynamicsAxVersion { get; init; }
}
/// Summary of a database discovery; the databases themselves are in insight.ConfiguredDatabases.
public sealed record DatabaseDiscoveryResult
{
public int Databases { get; init; }
public IReadOnlyList New { get; init; } = [];
public IReadOnlyList Gone { get; init; } = [];
/// New databases were monitored at once (the instance monitors new databases automatically).
public bool NewMonitored { get; init; }
public string? Error { get; init; }
public string? Hint { get; init; }
}
/// A SQL Server instance found on a computer.
/// What to type as the server: HOST or HOST\INSTANCE.
/// Where it was found (Danish): "SQL Server Browser" or "registreringsdatabasen".
public sealed record DiscoveredInstance(string Server, string InstanceName, string? Version, int? TcpPort, bool IsClustered, string Source);
public sealed record InstanceDiscoveryResult
{
public string Host { get; init; } = string.Empty;
public IReadOnlyList Instances { get; init; } = [];
public IReadOnlyList Notes { get; init; } = [];
}