/* 1.5: Windows servers and synthetic checks. WindowsServers the Windows servers the agent looks at: the computers behind the monitored SQL Server instances (Source 'SqlHost', kept in step by the agent) and servers added in SQLInsight Web (AOS and other application servers, file servers). The agent reads them remotely, as its own identity, with least privilege (db/permissions/grant-windows-server.ps1); it never changes them. ServerPerformance CPU, available memory, paging and commit per minute. Kept SQLInsight:Servers:SampleDays. ServerDiskSamples free space per volume every 15 minutes: the history the "fuld om ca. N dage" forecast is computed from. Kept SQLInsight:Servers:DiskHistoryDays. ServerEvents errors and critical events from the System and Application logs, summed per collection, source and event id like insight.ErrorLogEvents. Sample is a message: local only. Kept EventDays. ServerSnapshots the latest collection per area (services, tasks, disks with forecasts …) for display, and so a restarted agent continues where it stopped. SyntheticChecks checks the agent runs on a schedule: TCP port, HTTP(S), SQL login + query, DNS, Dynamics AX logon. A SQL login password is sealed with the agent's public key (insight.AgentKeys), as in 1.3. SyntheticCheckResults every run, kept SQLInsight:SyntheticChecks:ResultDays. ServerFindings, findings and rule outcomes of the Windows server rules (Scope 'Server') and synthetic check rules ServerRuleStates (Scope 'Check'), like insight.Findings and insight.RuleStates for instances. */ CREATE TABLE insight.WindowsServers ( ServerId int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_WindowsServers PRIMARY KEY, Name nvarchar(128) NOT NULL, Host nvarchar(255) NOT NULL, Role varchar(16) NOT NULL CONSTRAINT DF_WindowsServers_Role DEFAULT ('Other') CONSTRAINT CK_WindowsServers_Role CHECK (Role IN ('Sql', 'Application', 'File', 'Other')), Source varchar(16) NOT NULL CONSTRAINT DF_WindowsServers_Source DEFAULT ('Web') CONSTRAINT CK_WindowsServers_Source CHECK (Source IN ('Web', 'SqlHost')), Paused bit NOT NULL CONSTRAINT DF_WindowsServers_Paused DEFAULT (0), WatchedServices nvarchar(max) NULL, IgnoredServices nvarchar(max) NULL, CreatedAt datetime2(0) NOT NULL CONSTRAINT DF_WindowsServers_CreatedAt DEFAULT (SYSUTCDATETIME()), CreatedBy nvarchar(256) NULL, UpdatedAt datetime2(0) NOT NULL CONSTRAINT DF_WindowsServers_UpdatedAt DEFAULT (SYSUTCDATETIME()), UpdatedBy nvarchar(256) NULL, RemovedAt datetime2(0) NULL, RemovedBy nvarchar(256) NULL, /* What the agent saw. */ LastContactAt datetime2(0) NULL, LastErrorAt datetime2(0) NULL, LastError nvarchar(1000) NULL, Protocol varchar(16) NULL, OperatingSystem nvarchar(256) NULL, OsVersion nvarchar(64) NULL, LastBootUpTime datetime2(0) NULL, TotalMemoryMb float NULL, LogicalProcessors int NULL, AreasJson nvarchar(max) NULL ); CREATE UNIQUE INDEX UQ_WindowsServers_Host ON insight.WindowsServers (Host) WHERE RemovedAt IS NULL; CREATE UNIQUE INDEX UQ_WindowsServers_Name ON insight.WindowsServers (Name) WHERE RemovedAt IS NULL; CREATE TABLE insight.ServerPerformance ( ServerId int NOT NULL, SampledAt datetime2(0) NOT NULL, CpuPercent real NULL, AvailableMb real NULL, AvailablePct real NULL, PagesPerSec real NULL, CommitPct real NULL, CONSTRAINT PK_ServerPerformance PRIMARY KEY (ServerId, SampledAt) ); /* Retention deletes by time across all servers. */ CREATE INDEX IX_ServerPerformance_SampledAt ON insight.ServerPerformance (SampledAt); CREATE TABLE insight.ServerDiskSamples ( ServerId int NOT NULL, Volume nvarchar(260) NOT NULL, SampledAt datetime2(0) NOT NULL, SizeGb float NOT NULL, FreeGb float NOT NULL, CONSTRAINT PK_ServerDiskSamples PRIMARY KEY (ServerId, Volume, SampledAt) ); CREATE INDEX IX_ServerDiskSamples_SampledAt ON insight.ServerDiskSamples (SampledAt); CREATE TABLE insight.ServerEvents ( EventRowId bigint IDENTITY(1, 1) NOT NULL CONSTRAINT PK_ServerEvents PRIMARY KEY NONCLUSTERED, ServerId int NOT NULL, CollectedAt datetime2(0) NOT NULL, LogName nvarchar(64) NOT NULL, Source nvarchar(256) NOT NULL, EventId bigint NOT NULL, [Level] tinyint NOT NULL, Category varchar(32) NOT NULL, [Count] int NOT NULL, FirstAt datetime2(0) NOT NULL, LastAt datetime2(0) NOT NULL, Sample nvarchar(500) NULL ); CREATE CLUSTERED INDEX CX_ServerEvents ON insight.ServerEvents (ServerId, LastAt); CREATE INDEX IX_ServerEvents_LastAt ON insight.ServerEvents (LastAt); CREATE TABLE insight.ServerSnapshots ( ServerId int NOT NULL, Area varchar(32) NOT NULL, CapturedAt datetime2(0) NOT NULL, Json nvarchar(max) NOT NULL, CONSTRAINT PK_ServerSnapshots PRIMARY KEY (ServerId, Area) ); CREATE TABLE insight.SyntheticChecks ( CheckId int IDENTITY(1, 1) NOT NULL CONSTRAINT PK_SyntheticChecks PRIMARY KEY, Name nvarchar(128) NOT NULL, Kind varchar(16) NOT NULL CONSTRAINT CK_SyntheticChecks_Kind CHECK (Kind IN ('Tcp', 'Http', 'Sql', 'Dns', 'AxLogon')), ServerId int NULL CONSTRAINT FK_SyntheticChecks_Server REFERENCES insight.WindowsServers (ServerId), SettingsJson nvarchar(max) NOT NULL, SecretCipher varbinary(2048) NULL, SecretKeyId varchar(64) NULL, IntervalSeconds int NOT NULL CONSTRAINT DF_SyntheticChecks_Interval DEFAULT (300) CONSTRAINT CK_SyntheticChecks_Interval CHECK (IntervalSeconds BETWEEN 60 AND 86400), TimeoutSeconds int NOT NULL CONSTRAINT DF_SyntheticChecks_Timeout DEFAULT (15) CONSTRAINT CK_SyntheticChecks_Timeout CHECK (TimeoutSeconds BETWEEN 1 AND 120), Paused bit NOT NULL CONSTRAINT DF_SyntheticChecks_Paused DEFAULT (0), CreatedAt datetime2(0) NOT NULL CONSTRAINT DF_SyntheticChecks_CreatedAt DEFAULT (SYSUTCDATETIME()), CreatedBy nvarchar(256) NULL, UpdatedAt datetime2(0) NOT NULL CONSTRAINT DF_SyntheticChecks_UpdatedAt DEFAULT (SYSUTCDATETIME()), UpdatedBy nvarchar(256) NULL, RemovedAt datetime2(0) NULL, RemovedBy nvarchar(256) NULL, SecretError nvarchar(1000) NULL, /* What the agent saw. */ LastRunAt datetime2(0) NULL, LastSuccess bit NULL, LastDurationMs int NULL, LastMessage nvarchar(1000) NULL, ConsecutiveFailures int NOT NULL CONSTRAINT DF_SyntheticChecks_Failures DEFAULT (0) ); CREATE UNIQUE INDEX UQ_SyntheticChecks_Name ON insight.SyntheticChecks (Name) WHERE RemovedAt IS NULL; CREATE TABLE insight.SyntheticCheckResults ( ResultId bigint IDENTITY(1, 1) NOT NULL CONSTRAINT PK_SyntheticCheckResults PRIMARY KEY NONCLUSTERED, CheckId int NOT NULL, RunAt datetime2(0) NOT NULL, Success bit NOT NULL, DurationMs int NOT NULL, Message nvarchar(1000) NOT NULL, DetailsJson nvarchar(4000) NULL, CertificateExpiresAt datetime2(0) NULL, CertificateSubject nvarchar(400) NULL, ServiceState varchar(32) NULL, [Partial] bit NOT NULL CONSTRAINT DF_SyntheticCheckResults_Partial DEFAULT (0) ); CREATE CLUSTERED INDEX CX_SyntheticCheckResults ON insight.SyntheticCheckResults (CheckId, RunAt); CREATE INDEX IX_SyntheticCheckResults_RunAt ON insight.SyntheticCheckResults (RunAt); CREATE TABLE insight.ServerFindings ( FindingId bigint IDENTITY(1, 1) NOT NULL CONSTRAINT PK_ServerFindings PRIMARY KEY, Scope varchar(8) NOT NULL CONSTRAINT CK_ServerFindings_Scope CHECK (Scope IN ('Server', 'Check')), ScopeId int NOT NULL, RuleId varchar(40) NOT NULL, Subject nvarchar(400) NOT NULL, Severity tinyint NOT NULL, Title nvarchar(1000) NOT NULL, Explanation nvarchar(max) NOT NULL, Recommendation nvarchar(max) NOT NULL, EvidenceJson nvarchar(max) NOT NULL, ReferencesJson nvarchar(max) NOT NULL, FirstSeenAt datetime2(0) NOT NULL, LastSeenAt datetime2(0) NOT NULL, ResolvedAt datetime2(0) NULL ); CREATE UNIQUE INDEX UX_ServerFindings_Active ON insight.ServerFindings (Scope, ScopeId, RuleId, Subject) WHERE ResolvedAt IS NULL; CREATE INDEX IX_ServerFindings_Resolved ON insight.ServerFindings (ResolvedAt) WHERE ResolvedAt IS NOT NULL; CREATE TABLE insight.ServerRuleStates ( Scope varchar(8) NOT NULL, ScopeId int NOT NULL, RuleId varchar(40) NOT NULL, RuleTitle nvarchar(400) NOT NULL, Outcome tinyint NOT NULL, Reason nvarchar(max) NULL, EvaluatedAt datetime2(0) NOT NULL, CONSTRAINT PK_ServerRuleStates PRIMARY KEY (Scope, ScopeId, RuleId) ); /* Requests about a Windows server or a synthetic check name it in TargetId. */ ALTER TABLE insight.AgentRequests ADD TargetId int NULL; ALTER TABLE insight.AgentRequests DROP CONSTRAINT CK_AgentRequests_Kind; ALTER TABLE insight.AgentRequests ADD CONSTRAINT CK_AgentRequests_Kind CHECK (Kind IN ('ConnectionTest', 'DatabaseDiscovery', 'InstanceDiscovery', 'ServerTest', 'SyntheticCheckRun')); GO CREATE INDEX IX_AgentRequests_Target ON insight.AgentRequests (Kind, TargetId, RequestId) WHERE TargetId IS NOT NULL; GO /* SQLInsight Web only has db_datareader. As in 0016 it gets exactly what it needs to change the configuration: add servers and checks, change what may be changed, and remove (RemovedAt, no DELETE; a removed check's sealed password and last message are cleared, and checks of a removed server lose the server). Nothing else the agent records. Host, Name of a server and Kind of a check are fixed once created. Who may change it in the web UI is decided by SQLInsight:Web:AdminGroups. */ GRANT INSERT ON insight.WindowsServers TO public; GRANT UPDATE ON insight.WindowsServers (Role, Paused, WatchedServices, IgnoredServices, UpdatedAt, UpdatedBy, RemovedAt, RemovedBy) TO public; GRANT INSERT ON insight.SyntheticChecks TO public; GRANT UPDATE ON insight.SyntheticChecks (Name, ServerId, SettingsJson, SecretCipher, SecretKeyId, IntervalSeconds, TimeoutSeconds, Paused, UpdatedAt, UpdatedBy, RemovedAt, RemovedBy, SecretError, LastMessage) TO public;