From 121983fd66468a63547ca29344fcf4cea0cf5c8f Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 17 Mar 2026 03:01:21 -0400 Subject: [PATCH] Add Rider launch profiles, fix DI and migrations for dev startup - Rider launch profiles: "ScadaLink Central" and "ScadaLink Site" - appsettings.Central.json: correct test_infra credentials (ScadaLink_Dev1#, scadalink_app user, GLAuth on 3893, Mailpit on 1025) - Fix HealthMonitoring DI: split site vs central registration to avoid missing IHealthReportTransport on central - Regenerate single clean EF migration (InitialSchema) covering all entities - Suppress PendingModelChangesWarning in dev mode - Fix isDevelopment check for ASPNETCORE_ENVIRONMENT propagation Verified: Host starts, connects to SQL Server, applies migrations, boots Akka.NET cluster, LDAP auth works (admin/password via GLAuth), health endpoint returns Healthy. --- .../20260316231104_InitialCreate.Designer.cs | 1144 ------------- .../Migrations/20260316231942_SeedData.cs | 28 - ... 20260317065749_InitialSchema.Designer.cs} | 74 +- ...ate.cs => 20260317065749_InitialSchema.cs} | 64 +- .../ScadaLinkDbContextModelSnapshot.cs | 70 + .../ServiceCollectionExtensions.cs | 4 +- .../ServiceCollectionExtensions.cs | 15 +- src/ScadaLink.Host/Program.cs | 4 +- .../Properties/launchSettings.json | 24 + src/ScadaLink.Host/appsettings.Central.json | 19 +- .../logs/scadalink-20260317.log | 1462 +++++++++++++++++ 11 files changed, 1721 insertions(+), 1187 deletions(-) delete mode 100644 src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.Designer.cs delete mode 100644 src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.cs rename src/ScadaLink.ConfigurationDatabase/Migrations/{20260316231942_SeedData.Designer.cs => 20260317065749_InitialSchema.Designer.cs} (94%) rename src/ScadaLink.ConfigurationDatabase/Migrations/{20260316231104_InitialCreate.cs => 20260317065749_InitialSchema.cs} (93%) create mode 100644 src/ScadaLink.Host/Properties/launchSettings.json create mode 100644 src/ScadaLink.Host/logs/scadalink-20260317.log diff --git a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.Designer.cs b/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.Designer.cs deleted file mode 100644 index 918196a..0000000 --- a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.Designer.cs +++ /dev/null @@ -1,1144 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using ScadaLink.ConfigurationDatabase; - -#nullable disable - -namespace ScadaLink.ConfigurationDatabase.Migrations -{ - [DbContext(typeof(ScadaLinkDbContext))] - [Migration("20260316231104_InitialCreate")] - partial class InitialCreate - { - /// - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "10.0.5") - .HasAnnotation("Relational:MaxIdentifierLength", 128); - - SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Audit.AuditLogEntry", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Action") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.Property("AfterStateJson") - .HasColumnType("nvarchar(max)"); - - b.Property("EntityId") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("EntityName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("EntityType") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("Timestamp") - .HasColumnType("datetimeoffset"); - - b.Property("User") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("Action"); - - b.HasIndex("EntityId"); - - b.HasIndex("EntityType"); - - b.HasIndex("Timestamp"); - - b.HasIndex("User"); - - b.ToTable("AuditLogEntries"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("CompletedAt") - .HasColumnType("datetimeoffset"); - - b.Property("DeployedAt") - .HasColumnType("datetimeoffset"); - - b.Property("DeployedBy") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("DeploymentId") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.Property("InstanceId") - .HasColumnType("int"); - - b.Property("RevisionHash") - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.Property("RowVersion") - .IsConcurrencyToken() - .ValueGeneratedOnAddOrUpdate() - .HasColumnType("rowversion"); - - b.Property("Status") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.HasKey("Id"); - - b.HasIndex("DeployedAt"); - - b.HasIndex("DeploymentId") - .IsUnique(); - - b.HasIndex("InstanceId"); - - b.ToTable("DeploymentRecords"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.SystemArtifactDeploymentRecord", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("ArtifactType") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.Property("DeployedAt") - .HasColumnType("datetimeoffset"); - - b.Property("DeployedBy") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("PerSiteStatus") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.HasKey("Id"); - - b.HasIndex("DeployedAt"); - - b.ToTable("SystemArtifactDeploymentRecords"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.DatabaseConnectionDefinition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("ConnectionString") - .IsRequired() - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("MaxRetries") - .HasColumnType("int"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("RetryDelay") - .HasColumnType("time"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("DatabaseConnectionDefinitions"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemDefinition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("AuthConfiguration") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("AuthType") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("EndpointUrl") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)"); - - b.Property("MaxRetries") - .HasColumnType("int"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("RetryDelay") - .HasColumnType("time"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("ExternalSystemDefinitions"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemMethod", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("ExternalSystemDefinitionId") - .HasColumnType("int"); - - b.Property("HttpMethod") - .IsRequired() - .HasMaxLength(10) - .HasColumnType("nvarchar(10)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("ParameterDefinitions") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("Path") - .IsRequired() - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)"); - - b.Property("ReturnDefinition") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.HasKey("Id"); - - b.HasIndex("ExternalSystemDefinitionId", "Name") - .IsUnique(); - - b.ToTable("ExternalSystemMethods"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.InboundApi.ApiKey", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("IsEnabled") - .HasColumnType("bit"); - - b.Property("KeyValue") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("KeyValue") - .IsUnique(); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("ApiKeys"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.InboundApi.ApiMethod", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("ApprovedApiKeyIds") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("ParameterDefinitions") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("ReturnDefinition") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("Script") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("TimeoutSeconds") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("ApiMethods"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Area", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("ParentAreaId") - .HasColumnType("int"); - - b.Property("SiteId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("ParentAreaId"); - - b.HasIndex("SiteId", "ParentAreaId", "Name") - .IsUnique() - .HasFilter("[ParentAreaId] IS NOT NULL"); - - b.ToTable("Areas"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Instance", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("AreaId") - .HasColumnType("int"); - - b.Property("SiteId") - .HasColumnType("int"); - - b.Property("State") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("TemplateId") - .HasColumnType("int"); - - b.Property("UniqueName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("AreaId"); - - b.HasIndex("TemplateId"); - - b.HasIndex("SiteId", "UniqueName") - .IsUnique(); - - b.ToTable("Instances"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceAttributeOverride", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("AttributeName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("InstanceId") - .HasColumnType("int"); - - b.Property("OverrideValue") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.HasKey("Id"); - - b.HasIndex("InstanceId", "AttributeName") - .IsUnique(); - - b.ToTable("InstanceAttributeOverrides"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceConnectionBinding", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("AttributeName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("DataConnectionId") - .HasColumnType("int"); - - b.Property("InstanceId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("DataConnectionId"); - - b.HasIndex("InstanceId", "AttributeName") - .IsUnique(); - - b.ToTable("InstanceConnectionBindings"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationList", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("NotificationLists"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationRecipient", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("EmailAddress") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("NotificationListId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("NotificationListId"); - - b.ToTable("NotificationRecipients"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.SmtpConfiguration", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("AuthType") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("ConnectionTimeoutSeconds") - .HasColumnType("int"); - - b.Property("Credentials") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("FromAddress") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property("Host") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property("MaxConcurrentConnections") - .HasColumnType("int"); - - b.Property("MaxRetries") - .HasColumnType("int"); - - b.Property("Port") - .HasColumnType("int"); - - b.Property("RetryDelay") - .HasColumnType("time"); - - b.Property("TlsMode") - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.HasKey("Id"); - - b.ToTable("SmtpConfigurations"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Scripts.SharedScript", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Code") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("ParameterDefinitions") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("ReturnDefinition") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("SharedScripts"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Security.LdapGroupMapping", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("LdapGroupName") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property("Role") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.HasKey("Id"); - - b.HasIndex("LdapGroupName") - .IsUnique(); - - b.ToTable("LdapGroupMappings"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Security.SiteScopeRule", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("LdapGroupMappingId") - .HasColumnType("int"); - - b.Property("SiteId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("SiteId"); - - b.HasIndex("LdapGroupMappingId", "SiteId") - .IsUnique(); - - b.ToTable("SiteScopeRules"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.DataConnection", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Configuration") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("Protocol") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.ToTable("DataConnections"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.Site", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("SiteIdentifier") - .IsRequired() - .HasMaxLength(100) - .HasColumnType("nvarchar(100)"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.HasIndex("SiteIdentifier") - .IsUnique(); - - b.ToTable("Sites"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.SiteDataConnectionAssignment", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("DataConnectionId") - .HasColumnType("int"); - - b.Property("SiteId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("DataConnectionId"); - - b.HasIndex("SiteId", "DataConnectionId") - .IsUnique(); - - b.ToTable("SiteDataConnectionAssignments"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.Template", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("ParentTemplateId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("Name") - .IsUnique(); - - b.HasIndex("ParentTemplateId"); - - b.ToTable("Templates"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAlarm", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)"); - - b.Property("IsLocked") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("OnTriggerScriptId") - .HasColumnType("int"); - - b.Property("PriorityLevel") - .HasColumnType("int"); - - b.Property("TemplateId") - .HasColumnType("int"); - - b.Property("TriggerConfiguration") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("TriggerType") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.HasKey("Id"); - - b.HasIndex("TemplateId", "Name") - .IsUnique(); - - b.ToTable("TemplateAlarms"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAttribute", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("DataSourceReference") - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property("DataType") - .IsRequired() - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.Property("Description") - .HasMaxLength(2000) - .HasColumnType("nvarchar(2000)"); - - b.Property("IsLocked") - .HasColumnType("bit"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("TemplateId") - .HasColumnType("int"); - - b.Property("Value") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.HasKey("Id"); - - b.HasIndex("TemplateId", "Name") - .IsUnique(); - - b.ToTable("TemplateAttributes"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateComposition", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("ComposedTemplateId") - .HasColumnType("int"); - - b.Property("InstanceName") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("TemplateId") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("ComposedTemplateId"); - - b.HasIndex("TemplateId", "InstanceName") - .IsUnique(); - - b.ToTable("TemplateCompositions"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateScript", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); - - b.Property("Code") - .IsRequired() - .HasColumnType("nvarchar(max)"); - - b.Property("IsLocked") - .HasColumnType("bit"); - - b.Property("MinTimeBetweenRuns") - .HasColumnType("time"); - - b.Property("Name") - .IsRequired() - .HasMaxLength(200) - .HasColumnType("nvarchar(200)"); - - b.Property("ParameterDefinitions") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("ReturnDefinition") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("TemplateId") - .HasColumnType("int"); - - b.Property("TriggerConfiguration") - .HasMaxLength(4000) - .HasColumnType("nvarchar(4000)"); - - b.Property("TriggerType") - .HasMaxLength(50) - .HasColumnType("nvarchar(50)"); - - b.HasKey("Id"); - - b.HasIndex("TemplateId", "Name") - .IsUnique(); - - b.ToTable("TemplateScripts"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b => - { - b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) - .WithMany() - .HasForeignKey("InstanceId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemMethod", b => - { - b.HasOne("ScadaLink.Commons.Entities.ExternalSystems.ExternalSystemDefinition", null) - .WithMany() - .HasForeignKey("ExternalSystemDefinitionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Area", b => - { - b.HasOne("ScadaLink.Commons.Entities.Instances.Area", null) - .WithMany("Children") - .HasForeignKey("ParentAreaId") - .OnDelete(DeleteBehavior.Restrict); - - b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null) - .WithMany() - .HasForeignKey("SiteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Instance", b => - { - b.HasOne("ScadaLink.Commons.Entities.Instances.Area", null) - .WithMany() - .HasForeignKey("AreaId") - .OnDelete(DeleteBehavior.SetNull); - - b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null) - .WithMany() - .HasForeignKey("SiteId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany() - .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceAttributeOverride", b => - { - b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) - .WithMany("AttributeOverrides") - .HasForeignKey("InstanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.InstanceConnectionBinding", b => - { - b.HasOne("ScadaLink.Commons.Entities.Sites.DataConnection", null) - .WithMany() - .HasForeignKey("DataConnectionId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) - .WithMany("ConnectionBindings") - .HasForeignKey("InstanceId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationRecipient", b => - { - b.HasOne("ScadaLink.Commons.Entities.Notifications.NotificationList", null) - .WithMany("Recipients") - .HasForeignKey("NotificationListId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Security.SiteScopeRule", b => - { - b.HasOne("ScadaLink.Commons.Entities.Security.LdapGroupMapping", null) - .WithMany() - .HasForeignKey("LdapGroupMappingId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null) - .WithMany() - .HasForeignKey("SiteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Sites.SiteDataConnectionAssignment", b => - { - b.HasOne("ScadaLink.Commons.Entities.Sites.DataConnection", null) - .WithMany() - .HasForeignKey("DataConnectionId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("ScadaLink.Commons.Entities.Sites.Site", null) - .WithMany() - .HasForeignKey("SiteId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.Template", b => - { - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany() - .HasForeignKey("ParentTemplateId") - .OnDelete(DeleteBehavior.Restrict); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAlarm", b => - { - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany("Alarms") - .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateAttribute", b => - { - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany("Attributes") - .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateComposition", b => - { - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany() - .HasForeignKey("ComposedTemplateId") - .OnDelete(DeleteBehavior.Restrict) - .IsRequired(); - - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany("Compositions") - .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.TemplateScript", b => - { - b.HasOne("ScadaLink.Commons.Entities.Templates.Template", null) - .WithMany("Scripts") - .HasForeignKey("TemplateId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Area", b => - { - b.Navigation("Children"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Instances.Instance", b => - { - b.Navigation("AttributeOverrides"); - - b.Navigation("ConnectionBindings"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Notifications.NotificationList", b => - { - b.Navigation("Recipients"); - }); - - modelBuilder.Entity("ScadaLink.Commons.Entities.Templates.Template", b => - { - b.Navigation("Alarms"); - - b.Navigation("Attributes"); - - b.Navigation("Compositions"); - - b.Navigation("Scripts"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.cs b/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.cs deleted file mode 100644 index c3fdb79..0000000 --- a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -namespace ScadaLink.ConfigurationDatabase.Migrations -{ - /// - public partial class SeedData : Migration - { - /// - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.InsertData( - table: "LdapGroupMappings", - columns: new[] { "Id", "LdapGroupName", "Role" }, - values: new object[] { 1, "SCADA-Admins", "Admin" }); - } - - /// - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "LdapGroupMappings", - keyColumn: "Id", - keyValue: 1); - } - } -} diff --git a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.Designer.cs b/src/ScadaLink.ConfigurationDatabase/Migrations/20260317065749_InitialSchema.Designer.cs similarity index 94% rename from src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.Designer.cs rename to src/ScadaLink.ConfigurationDatabase/Migrations/20260317065749_InitialSchema.Designer.cs index e8d03e4..2bbc992 100644 --- a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231942_SeedData.Designer.cs +++ b/src/ScadaLink.ConfigurationDatabase/Migrations/20260317065749_InitialSchema.Designer.cs @@ -12,8 +12,8 @@ using ScadaLink.ConfigurationDatabase; namespace ScadaLink.ConfigurationDatabase.Migrations { [DbContext(typeof(ScadaLinkDbContext))] - [Migration("20260316231942_SeedData")] - partial class SeedData + [Migration("20260317065749_InitialSchema")] + partial class InitialSchema { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -25,6 +25,25 @@ namespace ScadaLink.ConfigurationDatabase.Migrations SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FriendlyName") + .HasColumnType("nvarchar(max)"); + + b.Property("Xml") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("DataProtectionKeys"); + }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Audit.AuditLogEntry", b => { b.Property("Id") @@ -79,6 +98,44 @@ namespace ScadaLink.ConfigurationDatabase.Migrations b.ToTable("AuditLogEntries"); }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeployedConfigSnapshot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConfigurationJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeployedAt") + .HasColumnType("datetimeoffset"); + + b.Property("DeploymentId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("InstanceId") + .HasColumnType("int"); + + b.Property("RevisionHash") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("DeploymentId"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DeployedConfigSnapshots"); + }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b => { b.Property("Id") @@ -103,6 +160,9 @@ namespace ScadaLink.ConfigurationDatabase.Migrations .HasMaxLength(100) .HasColumnType("nvarchar(100)"); + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + b.Property("InstanceId") .HasColumnType("int"); @@ -112,6 +172,7 @@ namespace ScadaLink.ConfigurationDatabase.Migrations b.Property("RowVersion") .IsConcurrencyToken() + .IsRequired() .ValueGeneratedOnAddOrUpdate() .HasColumnType("rowversion"); @@ -954,6 +1015,15 @@ namespace ScadaLink.ConfigurationDatabase.Migrations b.ToTable("TemplateScripts"); }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeployedConfigSnapshot", b => + { + b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) + .WithMany() + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b => { b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) diff --git a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.cs b/src/ScadaLink.ConfigurationDatabase/Migrations/20260317065749_InitialSchema.cs similarity index 93% rename from src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.cs rename to src/ScadaLink.ConfigurationDatabase/Migrations/20260317065749_InitialSchema.cs index 2ceed63..e3e5923 100644 --- a/src/ScadaLink.ConfigurationDatabase/Migrations/20260316231104_InitialCreate.cs +++ b/src/ScadaLink.ConfigurationDatabase/Migrations/20260317065749_InitialSchema.cs @@ -6,7 +6,7 @@ using Microsoft.EntityFrameworkCore.Migrations; namespace ScadaLink.ConfigurationDatabase.Migrations { /// - public partial class InitialCreate : Migration + public partial class InitialSchema : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) @@ -94,6 +94,20 @@ namespace ScadaLink.ConfigurationDatabase.Migrations table.PrimaryKey("PK_DataConnections", x => x.Id); }); + migrationBuilder.CreateTable( + name: "DataProtectionKeys", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + FriendlyName = table.Column(type: "nvarchar(max)", nullable: true), + Xml = table.Column(type: "nvarchar(max)", nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_DataProtectionKeys", x => x.Id); + }); + migrationBuilder.CreateTable( name: "ExternalSystemDefinitions", columns: table => new @@ -493,6 +507,29 @@ namespace ScadaLink.ConfigurationDatabase.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "DeployedConfigSnapshots", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + InstanceId = table.Column(type: "int", nullable: false), + DeploymentId = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + RevisionHash = table.Column(type: "nvarchar(100)", maxLength: 100, nullable: false), + ConfigurationJson = table.Column(type: "nvarchar(max)", nullable: false), + DeployedAt = table.Column(type: "datetimeoffset", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_DeployedConfigSnapshots", x => x.Id); + table.ForeignKey( + name: "FK_DeployedConfigSnapshots_Instances_InstanceId", + column: x => x.InstanceId, + principalTable: "Instances", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + migrationBuilder.CreateTable( name: "DeploymentRecords", columns: table => new @@ -506,7 +543,8 @@ namespace ScadaLink.ConfigurationDatabase.Migrations DeployedBy = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), DeployedAt = table.Column(type: "datetimeoffset", nullable: false), CompletedAt = table.Column(type: "datetimeoffset", nullable: true), - RowVersion = table.Column(type: "rowversion", rowVersion: true, nullable: true) + ErrorMessage = table.Column(type: "nvarchar(max)", nullable: true), + RowVersion = table.Column(type: "rowversion", rowVersion: true, nullable: false) }, constraints: table => { @@ -567,6 +605,11 @@ namespace ScadaLink.ConfigurationDatabase.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.InsertData( + table: "LdapGroupMappings", + columns: new[] { "Id", "LdapGroupName", "Role" }, + values: new object[] { 1, "SCADA-Admins", "Admin" }); + migrationBuilder.CreateIndex( name: "IX_ApiKeys_KeyValue", table: "ApiKeys", @@ -634,6 +677,17 @@ namespace ScadaLink.ConfigurationDatabase.Migrations column: "Name", unique: true); + migrationBuilder.CreateIndex( + name: "IX_DeployedConfigSnapshots_DeploymentId", + table: "DeployedConfigSnapshots", + column: "DeploymentId"); + + migrationBuilder.CreateIndex( + name: "IX_DeployedConfigSnapshots_InstanceId", + table: "DeployedConfigSnapshots", + column: "InstanceId", + unique: true); + migrationBuilder.CreateIndex( name: "IX_DeploymentRecords_DeployedAt", table: "DeploymentRecords", @@ -813,6 +867,12 @@ namespace ScadaLink.ConfigurationDatabase.Migrations migrationBuilder.DropTable( name: "DatabaseConnectionDefinitions"); + migrationBuilder.DropTable( + name: "DataProtectionKeys"); + + migrationBuilder.DropTable( + name: "DeployedConfigSnapshots"); + migrationBuilder.DropTable( name: "DeploymentRecords"); diff --git a/src/ScadaLink.ConfigurationDatabase/Migrations/ScadaLinkDbContextModelSnapshot.cs b/src/ScadaLink.ConfigurationDatabase/Migrations/ScadaLinkDbContextModelSnapshot.cs index 5557550..b767753 100644 --- a/src/ScadaLink.ConfigurationDatabase/Migrations/ScadaLinkDbContextModelSnapshot.cs +++ b/src/ScadaLink.ConfigurationDatabase/Migrations/ScadaLinkDbContextModelSnapshot.cs @@ -22,6 +22,25 @@ namespace ScadaLink.ConfigurationDatabase.Migrations SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("FriendlyName") + .HasColumnType("nvarchar(max)"); + + b.Property("Xml") + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("DataProtectionKeys"); + }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Audit.AuditLogEntry", b => { b.Property("Id") @@ -76,6 +95,44 @@ namespace ScadaLink.ConfigurationDatabase.Migrations b.ToTable("AuditLogEntries"); }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeployedConfigSnapshot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ConfigurationJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DeployedAt") + .HasColumnType("datetimeoffset"); + + b.Property("DeploymentId") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("InstanceId") + .HasColumnType("int"); + + b.Property("RevisionHash") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("Id"); + + b.HasIndex("DeploymentId"); + + b.HasIndex("InstanceId") + .IsUnique(); + + b.ToTable("DeployedConfigSnapshots"); + }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b => { b.Property("Id") @@ -100,6 +157,9 @@ namespace ScadaLink.ConfigurationDatabase.Migrations .HasMaxLength(100) .HasColumnType("nvarchar(100)"); + b.Property("ErrorMessage") + .HasColumnType("nvarchar(max)"); + b.Property("InstanceId") .HasColumnType("int"); @@ -109,6 +169,7 @@ namespace ScadaLink.ConfigurationDatabase.Migrations b.Property("RowVersion") .IsConcurrencyToken() + .IsRequired() .ValueGeneratedOnAddOrUpdate() .HasColumnType("rowversion"); @@ -951,6 +1012,15 @@ namespace ScadaLink.ConfigurationDatabase.Migrations b.ToTable("TemplateScripts"); }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeployedConfigSnapshot", b => + { + b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) + .WithMany() + .HasForeignKey("InstanceId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + modelBuilder.Entity("ScadaLink.Commons.Entities.Deployment.DeploymentRecord", b => { b.HasOne("ScadaLink.Commons.Entities.Instances.Instance", null) diff --git a/src/ScadaLink.ConfigurationDatabase/ServiceCollectionExtensions.cs b/src/ScadaLink.ConfigurationDatabase/ServiceCollectionExtensions.cs index b13e6dc..4ade9dd 100644 --- a/src/ScadaLink.ConfigurationDatabase/ServiceCollectionExtensions.cs +++ b/src/ScadaLink.ConfigurationDatabase/ServiceCollectionExtensions.cs @@ -16,7 +16,9 @@ public static class ServiceCollectionExtensions public static IServiceCollection AddConfigurationDatabase(this IServiceCollection services, string connectionString) { services.AddDbContext(options => - options.UseSqlServer(connectionString)); + options.UseSqlServer(connectionString) + .ConfigureWarnings(w => w.Ignore( + Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))); services.AddScoped(); services.AddScoped(); diff --git a/src/ScadaLink.HealthMonitoring/ServiceCollectionExtensions.cs b/src/ScadaLink.HealthMonitoring/ServiceCollectionExtensions.cs index 64353c0..d18774a 100644 --- a/src/ScadaLink.HealthMonitoring/ServiceCollectionExtensions.cs +++ b/src/ScadaLink.HealthMonitoring/ServiceCollectionExtensions.cs @@ -5,12 +5,23 @@ namespace ScadaLink.HealthMonitoring; public static class ServiceCollectionExtensions { /// - /// Register site-side health monitoring services. + /// Register site-side health monitoring services (metric collection + periodic reporting). + /// Call this on site nodes only. For central, call AddCentralHealthAggregation() instead. + /// + public static IServiceCollection AddSiteHealthMonitoring(this IServiceCollection services) + { + services.AddSingleton(); + services.AddHostedService(); + return services; + } + + /// + /// Register shared health monitoring services (safe for both central and site). + /// Does not start the HealthReportSender — call AddSiteHealthMonitoring() on site nodes for that. /// public static IServiceCollection AddHealthMonitoring(this IServiceCollection services) { services.AddSingleton(); - services.AddHostedService(); return services; } diff --git a/src/ScadaLink.Host/Program.cs b/src/ScadaLink.Host/Program.cs index 7c232f8..4ff4ab0 100644 --- a/src/ScadaLink.Host/Program.cs +++ b/src/ScadaLink.Host/Program.cs @@ -65,6 +65,7 @@ try builder.Services.AddClusterInfrastructure(); builder.Services.AddCommunication(); builder.Services.AddHealthMonitoring(); + builder.Services.AddCentralHealthAggregation(); builder.Services.AddExternalSystemGateway(); builder.Services.AddNotificationService(); @@ -98,7 +99,8 @@ try // Apply or validate database migrations (skip when running in test harness) if (!string.Equals(configuration["ScadaLink:Database:SkipMigrations"], "true", StringComparison.OrdinalIgnoreCase)) { - var isDevelopment = app.Environment.IsDevelopment(); + var isDevelopment = app.Environment.IsDevelopment() + || string.Equals(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"), "Development", StringComparison.OrdinalIgnoreCase); using (var scope = app.Services.CreateScope()) { var dbContext = scope.ServiceProvider.GetRequiredService(); diff --git a/src/ScadaLink.Host/Properties/launchSettings.json b/src/ScadaLink.Host/Properties/launchSettings.json new file mode 100644 index 0000000..cacf775 --- /dev/null +++ b/src/ScadaLink.Host/Properties/launchSettings.json @@ -0,0 +1,24 @@ +{ + "profiles": { + "ScadaLink Central": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "launchUrl": "", + "applicationUrl": "https://localhost:5001;http://localhost:5000", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Central", + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "ScadaLink Site": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Site", + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/src/ScadaLink.Host/appsettings.Central.json b/src/ScadaLink.Host/appsettings.Central.json index 2c888a3..d9da746 100644 --- a/src/ScadaLink.Host/appsettings.Central.json +++ b/src/ScadaLink.Host/appsettings.Central.json @@ -2,13 +2,13 @@ "ScadaLink": { "Node": { "Role": "Central", - "NodeHostname": "central-node1", + "NodeHostname": "localhost", "RemotingPort": 8081 }, "Cluster": { "SeedNodes": [ - "akka.tcp://scadalink@central-node1:8081", - "akka.tcp://scadalink@central-node2:8081" + "akka.tcp://scadalink@localhost:8081", + "akka.tcp://scadalink@localhost:8082" ], "SplitBrainResolverStrategy": "keep-oldest", "StableAfter": "00:00:15", @@ -17,8 +17,8 @@ "MinNrOfMembers": 1 }, "Database": { - "ConfigurationDb": "Server=localhost,1433;Database=ScadaLink_Config;User Id=sa;Password=YourPassword;TrustServerCertificate=True", - "MachineDataDb": "Server=localhost,1433;Database=ScadaLink_MachineData;User Id=sa;Password=YourPassword;TrustServerCertificate=True" + "ConfigurationDb": "Server=localhost,1433;Database=ScadaLinkConfig;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true", + "MachineDataDb": "Server=localhost,1433;Database=ScadaLinkMachineData;User Id=scadalink_app;Password=ScadaLink_Dev1#;TrustServerCertificate=true" }, "Security": { "LdapServer": "localhost", @@ -26,7 +26,7 @@ "LdapUseTls": false, "AllowInsecureLdap": true, "LdapSearchBase": "dc=scadalink,dc=local", - "JwtSigningKey": "CHANGE-ME-development-signing-key-at-least-32-chars", + "JwtSigningKey": "scadalink-dev-jwt-signing-key-must-be-at-least-32-characters-long", "JwtExpiryMinutes": 15, "IdleTimeoutMinutes": 30 }, @@ -44,7 +44,12 @@ "InboundApi": { "DefaultMethodTimeout": "00:00:30" }, - "Notification": {}, + "Notification": { + "SmtpServer": "localhost", + "SmtpPort": 1025, + "AuthMode": "None", + "FromAddress": "scada-notifications@company.com" + }, "Logging": { "MinimumLevel": "Information" } diff --git a/src/ScadaLink.Host/logs/scadalink-20260317.log b/src/ScadaLink.Host/logs/scadalink-20260317.log new file mode 100644 index 0000000..42d0f55 --- /dev/null +++ b/src/ScadaLink.Host/logs/scadalink-20260317.log @@ -0,0 +1,1462 @@ +2026-03-17 02:51:23.401 -04:00 [INF] Starting ScadaLink host as Central on central-node1 +2026-03-17 02:51:51.085 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:51:51.544 -04:00 [INF] Executed DbCommand (12ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:51:51.564 -04:00 [INF] Executed DbCommand (14ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:51:51.565 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.InvalidOperationException: Database schema is out of date. 2 pending migration(s): 20260316231104_InitialCreate, 20260316231942_SeedData. Apply migrations using 'dotnet ef database update' or the generated SQL scripts before starting in production mode. + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 35 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 105 +2026-03-17 02:52:36.785 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:52:37.240 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:52:37.256 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:52:37.258 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.InvalidOperationException: Database schema is out of date. 2 pending migration(s): 20260316231104_InitialCreate, 20260316231942_SeedData. Apply migrations using 'dotnet ef database update' or the generated SQL scripts before starting in production mode. + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 35 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 105 +2026-03-17 02:53:23.914 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:53:24.359 -04:00 [INF] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:53:24.374 -04:00 [INF] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:53:24.376 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.InvalidOperationException: Database schema is out of date. 2 pending migration(s): 20260316231104_InitialCreate, 20260316231942_SeedData. Apply migrations using 'dotnet ef database update' or the generated SQL scripts before starting in production mode. + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 35 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 105 +2026-03-17 02:54:23.181 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:54:23.622 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.InvalidOperationException: An error was generated for warning 'Microsoft.EntityFrameworkCore.Migrations.PendingModelChangesWarning': The model for context 'ScadaLinkDbContext' has pending changes. Add a new migration before updating the database. See https://aka.ms/efcore-docs-pending-changes. This exception can be suppressed or logged by passing event ID 'RelationalEventId.PendingModelChangesWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'. + at Microsoft.EntityFrameworkCore.Diagnostics.EventDefinition`1.Log[TLoggerCategory](IDiagnosticsLogger`1 logger, TParam arg) + at Microsoft.EntityFrameworkCore.Diagnostics.RelationalLoggerExtensions.PendingModelChangesWarning(IDiagnosticsLogger`1 diagnostics, Type contextType) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.ValidateMigrations(Boolean useTransaction, String targetMigration) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 27 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 106 +2026-03-17 02:55:40.774 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:55:41.225 -04:00 [INF] Executed DbCommand (13ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:55:41.230 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 02:55:41.255 -04:00 [INF] Executed DbCommand (24ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 02:55:41.308 -04:00 [INF] Executed DbCommand (7ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 02:55:41.322 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:55:41.326 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:55:41.340 -04:00 [INF] Executed DbCommand (13ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 02:55:41.345 -04:00 [INF] Applying migration '20260316231104_InitialCreate'. +2026-03-17 02:55:41.376 -04:00 [INF] Executed DbCommand (5ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ApiKeys] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [KeyValue] nvarchar(500) NOT NULL, + [IsEnabled] bit NOT NULL, + CONSTRAINT [PK_ApiKeys] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.386 -04:00 [INF] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ApiMethods] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Script] nvarchar(max) NOT NULL, + [ApprovedApiKeyIds] nvarchar(4000) NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + [TimeoutSeconds] int NOT NULL, + CONSTRAINT [PK_ApiMethods] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.391 -04:00 [INF] Executed DbCommand (5ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [AuditLogEntries] ( + [Id] int NOT NULL IDENTITY, + [User] nvarchar(200) NOT NULL, + [Action] nvarchar(100) NOT NULL, + [EntityType] nvarchar(200) NOT NULL, + [EntityId] nvarchar(200) NOT NULL, + [EntityName] nvarchar(200) NOT NULL, + [AfterStateJson] nvarchar(max) NULL, + [Timestamp] datetimeoffset NOT NULL, + CONSTRAINT [PK_AuditLogEntries] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.395 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DatabaseConnectionDefinitions] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [ConnectionString] nvarchar(4000) NOT NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_DatabaseConnectionDefinitions] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.397 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DataConnections] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Protocol] nvarchar(50) NOT NULL, + [Configuration] nvarchar(4000) NULL, + CONSTRAINT [PK_DataConnections] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.401 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ExternalSystemDefinitions] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [EndpointUrl] nvarchar(2000) NOT NULL, + [AuthType] nvarchar(50) NOT NULL, + [AuthConfiguration] nvarchar(4000) NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_ExternalSystemDefinitions] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.403 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [LdapGroupMappings] ( + [Id] int NOT NULL IDENTITY, + [LdapGroupName] nvarchar(500) NOT NULL, + [Role] nvarchar(100) NOT NULL, + CONSTRAINT [PK_LdapGroupMappings] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.404 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [NotificationLists] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + CONSTRAINT [PK_NotificationLists] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.406 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SharedScripts] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Code] nvarchar(max) NOT NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + CONSTRAINT [PK_SharedScripts] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.408 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Sites] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [SiteIdentifier] nvarchar(100) NOT NULL, + [Description] nvarchar(2000) NULL, + CONSTRAINT [PK_Sites] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.410 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SmtpConfigurations] ( + [Id] int NOT NULL IDENTITY, + [Host] nvarchar(500) NOT NULL, + [Port] int NOT NULL, + [AuthType] nvarchar(50) NOT NULL, + [Credentials] nvarchar(4000) NULL, + [TlsMode] nvarchar(50) NULL, + [FromAddress] nvarchar(500) NOT NULL, + [ConnectionTimeoutSeconds] int NOT NULL, + [MaxConcurrentConnections] int NOT NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_SmtpConfigurations] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.411 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SystemArtifactDeploymentRecords] ( + [Id] int NOT NULL IDENTITY, + [ArtifactType] nvarchar(100) NOT NULL, + [DeployedBy] nvarchar(200) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + [PerSiteStatus] nvarchar(4000) NULL, + CONSTRAINT [PK_SystemArtifactDeploymentRecords] PRIMARY KEY ([Id]) +); +2026-03-17 02:55:41.415 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Templates] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Description] nvarchar(2000) NULL, + [ParentTemplateId] int NULL, + CONSTRAINT [PK_Templates] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Templates_Templates_ParentTemplateId] FOREIGN KEY ([ParentTemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION +); +2026-03-17 02:55:41.417 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ExternalSystemMethods] ( + [Id] int NOT NULL IDENTITY, + [ExternalSystemDefinitionId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [HttpMethod] nvarchar(10) NOT NULL, + [Path] nvarchar(2000) NOT NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + CONSTRAINT [PK_ExternalSystemMethods] PRIMARY KEY ([Id]), + CONSTRAINT [FK_ExternalSystemMethods_ExternalSystemDefinitions_ExternalSystemDefinitionId] FOREIGN KEY ([ExternalSystemDefinitionId]) REFERENCES [ExternalSystemDefinitions] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.419 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [NotificationRecipients] ( + [Id] int NOT NULL IDENTITY, + [NotificationListId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [EmailAddress] nvarchar(500) NOT NULL, + CONSTRAINT [PK_NotificationRecipients] PRIMARY KEY ([Id]), + CONSTRAINT [FK_NotificationRecipients_NotificationLists_NotificationListId] FOREIGN KEY ([NotificationListId]) REFERENCES [NotificationLists] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.421 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Areas] ( + [Id] int NOT NULL IDENTITY, + [SiteId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [ParentAreaId] int NULL, + CONSTRAINT [PK_Areas] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Areas_Areas_ParentAreaId] FOREIGN KEY ([ParentAreaId]) REFERENCES [Areas] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_Areas_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.423 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SiteDataConnectionAssignments] ( + [Id] int NOT NULL IDENTITY, + [SiteId] int NOT NULL, + [DataConnectionId] int NOT NULL, + CONSTRAINT [PK_SiteDataConnectionAssignments] PRIMARY KEY ([Id]), + CONSTRAINT [FK_SiteDataConnectionAssignments_DataConnections_DataConnectionId] FOREIGN KEY ([DataConnectionId]) REFERENCES [DataConnections] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_SiteDataConnectionAssignments_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.425 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SiteScopeRules] ( + [Id] int NOT NULL IDENTITY, + [LdapGroupMappingId] int NOT NULL, + [SiteId] int NOT NULL, + CONSTRAINT [PK_SiteScopeRules] PRIMARY KEY ([Id]), + CONSTRAINT [FK_SiteScopeRules_LdapGroupMappings_LdapGroupMappingId] FOREIGN KEY ([LdapGroupMappingId]) REFERENCES [LdapGroupMappings] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_SiteScopeRules_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.427 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateAlarms] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [Description] nvarchar(2000) NULL, + [PriorityLevel] int NOT NULL, + [IsLocked] bit NOT NULL, + [TriggerType] nvarchar(50) NOT NULL, + [TriggerConfiguration] nvarchar(4000) NULL, + [OnTriggerScriptId] int NULL, + CONSTRAINT [PK_TemplateAlarms] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateAlarms_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.429 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateAttributes] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [Value] nvarchar(4000) NULL, + [DataType] nvarchar(50) NOT NULL, + [IsLocked] bit NOT NULL, + [Description] nvarchar(2000) NULL, + [DataSourceReference] nvarchar(500) NULL, + CONSTRAINT [PK_TemplateAttributes] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateAttributes_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.431 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateCompositions] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [ComposedTemplateId] int NOT NULL, + [InstanceName] nvarchar(200) NOT NULL, + CONSTRAINT [PK_TemplateCompositions] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateCompositions_Templates_ComposedTemplateId] FOREIGN KEY ([ComposedTemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_TemplateCompositions_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.433 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateScripts] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [IsLocked] bit NOT NULL, + [Code] nvarchar(max) NOT NULL, + [TriggerType] nvarchar(50) NULL, + [TriggerConfiguration] nvarchar(4000) NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + [MinTimeBetweenRuns] time NULL, + CONSTRAINT [PK_TemplateScripts] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateScripts_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.436 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Instances] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [SiteId] int NOT NULL, + [AreaId] int NULL, + [UniqueName] nvarchar(200) NOT NULL, + [State] nvarchar(50) NOT NULL, + CONSTRAINT [PK_Instances] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Instances_Areas_AreaId] FOREIGN KEY ([AreaId]) REFERENCES [Areas] ([Id]) ON DELETE SET NULL, + CONSTRAINT [FK_Instances_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_Instances_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION +); +2026-03-17 02:55:41.438 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DeploymentRecords] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [Status] nvarchar(50) NOT NULL, + [DeploymentId] nvarchar(100) NOT NULL, + [RevisionHash] nvarchar(100) NULL, + [DeployedBy] nvarchar(200) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + [CompletedAt] datetimeoffset NULL, + [RowVersion] rowversion NULL, + CONSTRAINT [PK_DeploymentRecords] PRIMARY KEY ([Id]), + CONSTRAINT [FK_DeploymentRecords_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE NO ACTION +); +2026-03-17 02:55:41.439 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [InstanceAttributeOverrides] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [AttributeName] nvarchar(200) NOT NULL, + [OverrideValue] nvarchar(4000) NULL, + CONSTRAINT [PK_InstanceAttributeOverrides] PRIMARY KEY ([Id]), + CONSTRAINT [FK_InstanceAttributeOverrides_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.441 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [InstanceConnectionBindings] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [AttributeName] nvarchar(200) NOT NULL, + [DataConnectionId] int NOT NULL, + CONSTRAINT [PK_InstanceConnectionBindings] PRIMARY KEY ([Id]), + CONSTRAINT [FK_InstanceConnectionBindings_DataConnections_DataConnectionId] FOREIGN KEY ([DataConnectionId]) REFERENCES [DataConnections] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_InstanceConnectionBindings_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:55:41.443 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiKeys_KeyValue] ON [ApiKeys] ([KeyValue]); +2026-03-17 02:55:41.444 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiKeys_Name] ON [ApiKeys] ([Name]); +2026-03-17 02:55:41.445 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiMethods_Name] ON [ApiMethods] ([Name]); +2026-03-17 02:55:41.446 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Areas_ParentAreaId] ON [Areas] ([ParentAreaId]); +2026-03-17 02:55:41.448 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Areas_SiteId_ParentAreaId_Name] ON [Areas] ([SiteId], [ParentAreaId], [Name]) WHERE [ParentAreaId] IS NOT NULL; +2026-03-17 02:55:41.449 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_Action] ON [AuditLogEntries] ([Action]); +2026-03-17 02:55:41.450 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_EntityId] ON [AuditLogEntries] ([EntityId]); +2026-03-17 02:55:41.451 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_EntityType] ON [AuditLogEntries] ([EntityType]); +2026-03-17 02:55:41.452 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_Timestamp] ON [AuditLogEntries] ([Timestamp]); +2026-03-17 02:55:41.452 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_User] ON [AuditLogEntries] ([User]); +2026-03-17 02:55:41.453 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DatabaseConnectionDefinitions_Name] ON [DatabaseConnectionDefinitions] ([Name]); +2026-03-17 02:55:41.454 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DataConnections_Name] ON [DataConnections] ([Name]); +2026-03-17 02:55:41.455 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeploymentRecords_DeployedAt] ON [DeploymentRecords] ([DeployedAt]); +2026-03-17 02:55:41.456 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DeploymentRecords_DeploymentId] ON [DeploymentRecords] ([DeploymentId]); +2026-03-17 02:55:41.456 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeploymentRecords_InstanceId] ON [DeploymentRecords] ([InstanceId]); +2026-03-17 02:55:41.457 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ExternalSystemDefinitions_Name] ON [ExternalSystemDefinitions] ([Name]); +2026-03-17 02:55:41.458 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ExternalSystemMethods_ExternalSystemDefinitionId_Name] ON [ExternalSystemMethods] ([ExternalSystemDefinitionId], [Name]); +2026-03-17 02:55:41.460 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_InstanceAttributeOverrides_InstanceId_AttributeName] ON [InstanceAttributeOverrides] ([InstanceId], [AttributeName]); +2026-03-17 02:55:41.461 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_InstanceConnectionBindings_DataConnectionId] ON [InstanceConnectionBindings] ([DataConnectionId]); +2026-03-17 02:55:41.461 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_InstanceConnectionBindings_InstanceId_AttributeName] ON [InstanceConnectionBindings] ([InstanceId], [AttributeName]); +2026-03-17 02:55:41.462 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Instances_AreaId] ON [Instances] ([AreaId]); +2026-03-17 02:55:41.464 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Instances_SiteId_UniqueName] ON [Instances] ([SiteId], [UniqueName]); +2026-03-17 02:55:41.465 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Instances_TemplateId] ON [Instances] ([TemplateId]); +2026-03-17 02:55:41.466 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_LdapGroupMappings_LdapGroupName] ON [LdapGroupMappings] ([LdapGroupName]); +2026-03-17 02:55:41.466 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_NotificationLists_Name] ON [NotificationLists] ([Name]); +2026-03-17 02:55:41.467 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_NotificationRecipients_NotificationListId] ON [NotificationRecipients] ([NotificationListId]); +2026-03-17 02:55:41.468 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SharedScripts_Name] ON [SharedScripts] ([Name]); +2026-03-17 02:55:41.469 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SiteDataConnectionAssignments_DataConnectionId] ON [SiteDataConnectionAssignments] ([DataConnectionId]); +2026-03-17 02:55:41.469 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SiteDataConnectionAssignments_SiteId_DataConnectionId] ON [SiteDataConnectionAssignments] ([SiteId], [DataConnectionId]); +2026-03-17 02:55:41.470 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Sites_Name] ON [Sites] ([Name]); +2026-03-17 02:55:41.471 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Sites_SiteIdentifier] ON [Sites] ([SiteIdentifier]); +2026-03-17 02:55:41.472 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SiteScopeRules_LdapGroupMappingId_SiteId] ON [SiteScopeRules] ([LdapGroupMappingId], [SiteId]); +2026-03-17 02:55:41.473 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SiteScopeRules_SiteId] ON [SiteScopeRules] ([SiteId]); +2026-03-17 02:55:41.473 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SystemArtifactDeploymentRecords_DeployedAt] ON [SystemArtifactDeploymentRecords] ([DeployedAt]); +2026-03-17 02:55:41.474 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateAlarms_TemplateId_Name] ON [TemplateAlarms] ([TemplateId], [Name]); +2026-03-17 02:55:41.475 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateAttributes_TemplateId_Name] ON [TemplateAttributes] ([TemplateId], [Name]); +2026-03-17 02:55:41.476 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_TemplateCompositions_ComposedTemplateId] ON [TemplateCompositions] ([ComposedTemplateId]); +2026-03-17 02:55:41.477 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateCompositions_TemplateId_InstanceName] ON [TemplateCompositions] ([TemplateId], [InstanceName]); +2026-03-17 02:55:41.478 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Templates_Name] ON [Templates] ([Name]); +2026-03-17 02:55:41.478 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Templates_ParentTemplateId] ON [Templates] ([ParentTemplateId]); +2026-03-17 02:55:41.480 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateScripts_TemplateId_Name] ON [TemplateScripts] ([TemplateId], [Name]); +2026-03-17 02:55:41.483 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'20260316231104_InitialCreate', N'10.0.5'); +2026-03-17 02:55:41.491 -04:00 [INF] Applying migration '20260316231942_SeedData'. +2026-03-17 02:55:41.559 -04:00 [INF] Executed DbCommand (49ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'LdapGroupName', N'Role') AND [object_id] = OBJECT_ID(N'[LdapGroupMappings]')) + SET IDENTITY_INSERT [LdapGroupMappings] ON; +INSERT INTO [LdapGroupMappings] ([Id], [LdapGroupName], [Role]) +VALUES (1, N'SCADA-Admins', N'Admin'); +IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'LdapGroupName', N'Role') AND [object_id] = OBJECT_ID(N'[LdapGroupMappings]')) + SET IDENTITY_INSERT [LdapGroupMappings] OFF; +2026-03-17 02:55:41.560 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'20260316231942_SeedData', N'10.0.5'); +2026-03-17 02:55:41.562 -04:00 [INF] Applying migration '20260317065526_PhaseUpdates'. +2026-03-17 02:55:41.645 -04:00 [ERR] Failed executing DbCommand (64ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @var nvarchar(max); +SELECT @var = QUOTENAME([d].[name]) +FROM [sys].[default_constraints] [d] +INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] +WHERE ([d].[parent_object_id] = OBJECT_ID(N'[DeploymentRecords]') AND [c].[name] = N'RowVersion'); +IF @var IS NOT NULL EXEC(N'ALTER TABLE [DeploymentRecords] DROP CONSTRAINT ' + @var + ';'); +UPDATE [DeploymentRecords] SET [RowVersion] = 0x WHERE [RowVersion] IS NULL; +ALTER TABLE [DeploymentRecords] ALTER COLUMN [RowVersion] rowversion NOT NULL; +ALTER TABLE [DeploymentRecords] ADD DEFAULT 0x FOR [RowVersion]; +2026-03-17 02:55:41.653 -04:00 [FTL] ScadaLink host terminated unexpectedly +Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot update a timestamp column. +Cannot alter column 'RowVersion' to be data type timestamp. + at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) + at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) + at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, SqlCommand command, Boolean callerHasConnectionLock, Boolean asyncClose) + at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) + at Microsoft.Data.SqlClient.SqlCommand.InternalEndExecuteNonQuery(IAsyncResult asyncResult, Boolean isInternal, String endMethod) + at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult) + at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult) + at Microsoft.Data.SqlClient.SqlCommand.<>c.b__193_1(IAsyncResult asyncResult) + at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization) +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteAsync(IReadOnlyList`1 migrationCommands, IRelationalConnection connection, MigrationExecutionState executionState, Boolean beginTransaction, Boolean commitTransaction, Nullable`1 isolationLevel, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteAsync(IReadOnlyList`1 migrationCommands, IRelationalConnection connection, MigrationExecutionState executionState, Boolean beginTransaction, Boolean commitTransaction, Nullable`1 isolationLevel, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQueryAsync(IReadOnlyList`1 migrationCommands, IRelationalConnection connection, MigrationExecutionState executionState, Boolean commitTransaction, Nullable`1 isolationLevel, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.<>c.<b__22_1>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 27 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 106 +ClientConnectionId:03655f63-f79a-4720-86a6-15aa6fdaaf9d +Error Number:272,State:1,Class:16 +2026-03-17 02:56:14.122 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:56:14.613 -04:00 [INF] Executed DbCommand (12ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:56:14.619 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 02:56:14.632 -04:00 [INF] Executed DbCommand (12ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 02:56:14.677 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 02:56:14.685 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:56:14.687 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:56:14.691 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 02:56:14.696 -04:00 [INF] Applying migration '20260317065526_PhaseUpdates'. +2026-03-17 02:56:14.750 -04:00 [ERR] Failed executing DbCommand (31ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @var nvarchar(max); +SELECT @var = QUOTENAME([d].[name]) +FROM [sys].[default_constraints] [d] +INNER JOIN [sys].[columns] [c] ON [d].[parent_column_id] = [c].[column_id] AND [d].[parent_object_id] = [c].[object_id] +WHERE ([d].[parent_object_id] = OBJECT_ID(N'[DeploymentRecords]') AND [c].[name] = N'RowVersion'); +IF @var IS NOT NULL EXEC(N'ALTER TABLE [DeploymentRecords] DROP CONSTRAINT ' + @var + ';'); +UPDATE [DeploymentRecords] SET [RowVersion] = 0x WHERE [RowVersion] IS NULL; +ALTER TABLE [DeploymentRecords] ALTER COLUMN [RowVersion] rowversion NOT NULL; +ALTER TABLE [DeploymentRecords] ADD DEFAULT 0x FOR [RowVersion]; +2026-03-17 02:56:14.755 -04:00 [FTL] ScadaLink host terminated unexpectedly +Microsoft.Data.SqlClient.SqlException (0x80131904): Cannot update a timestamp column. +Cannot alter column 'RowVersion' to be data type timestamp. + at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) + at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction) + at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, SqlCommand command, Boolean callerHasConnectionLock, Boolean asyncClose) + at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady) + at Microsoft.Data.SqlClient.SqlCommand.InternalEndExecuteNonQuery(IAsyncResult asyncResult, Boolean isInternal, String endMethod) + at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryInternal(IAsyncResult asyncResult) + at Microsoft.Data.SqlClient.SqlCommand.EndExecuteNonQueryAsync(IAsyncResult asyncResult) + at Microsoft.Data.SqlClient.SqlCommand.<>c.b__193_1(IAsyncResult asyncResult) + at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization) +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQueryAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteAsync(IReadOnlyList`1 migrationCommands, IRelationalConnection connection, MigrationExecutionState executionState, Boolean beginTransaction, Boolean commitTransaction, Nullable`1 isolationLevel, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteAsync(IReadOnlyList`1 migrationCommands, IRelationalConnection connection, MigrationExecutionState executionState, Boolean beginTransaction, Boolean commitTransaction, Nullable`1 isolationLevel, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQueryAsync(IReadOnlyList`1 migrationCommands, IRelationalConnection connection, MigrationExecutionState executionState, Boolean commitTransaction, Nullable`1 isolationLevel, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.<>c.<b__22_1>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 27 + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 106 +ClientConnectionId:e57a4430-752d-47a3-872b-72730c64224a +Error Number:272,State:1,Class:16 +2026-03-17 02:58:03.084 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:58:03.554 -04:00 [INF] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:58:03.559 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 02:58:03.575 -04:00 [INF] Executed DbCommand (15ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 02:58:03.621 -04:00 [INF] Executed DbCommand (6ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 02:58:03.640 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:58:03.642 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:58:03.668 -04:00 [INF] Executed DbCommand (25ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 02:58:03.673 -04:00 [INF] Applying migration '20260317065749_InitialSchema'. +2026-03-17 02:58:03.711 -04:00 [INF] Executed DbCommand (5ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ApiKeys] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [KeyValue] nvarchar(500) NOT NULL, + [IsEnabled] bit NOT NULL, + CONSTRAINT [PK_ApiKeys] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.715 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ApiMethods] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Script] nvarchar(max) NOT NULL, + [ApprovedApiKeyIds] nvarchar(4000) NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + [TimeoutSeconds] int NOT NULL, + CONSTRAINT [PK_ApiMethods] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.717 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [AuditLogEntries] ( + [Id] int NOT NULL IDENTITY, + [User] nvarchar(200) NOT NULL, + [Action] nvarchar(100) NOT NULL, + [EntityType] nvarchar(200) NOT NULL, + [EntityId] nvarchar(200) NOT NULL, + [EntityName] nvarchar(200) NOT NULL, + [AfterStateJson] nvarchar(max) NULL, + [Timestamp] datetimeoffset NOT NULL, + CONSTRAINT [PK_AuditLogEntries] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.719 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DatabaseConnectionDefinitions] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [ConnectionString] nvarchar(4000) NOT NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_DatabaseConnectionDefinitions] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.720 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DataConnections] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Protocol] nvarchar(50) NOT NULL, + [Configuration] nvarchar(4000) NULL, + CONSTRAINT [PK_DataConnections] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.721 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DataProtectionKeys] ( + [Id] int NOT NULL IDENTITY, + [FriendlyName] nvarchar(max) NULL, + [Xml] nvarchar(max) NULL, + CONSTRAINT [PK_DataProtectionKeys] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.723 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ExternalSystemDefinitions] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [EndpointUrl] nvarchar(2000) NOT NULL, + [AuthType] nvarchar(50) NOT NULL, + [AuthConfiguration] nvarchar(4000) NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_ExternalSystemDefinitions] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.724 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [LdapGroupMappings] ( + [Id] int NOT NULL IDENTITY, + [LdapGroupName] nvarchar(500) NOT NULL, + [Role] nvarchar(100) NOT NULL, + CONSTRAINT [PK_LdapGroupMappings] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.726 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [NotificationLists] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + CONSTRAINT [PK_NotificationLists] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.728 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SharedScripts] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Code] nvarchar(max) NOT NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + CONSTRAINT [PK_SharedScripts] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.729 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Sites] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [SiteIdentifier] nvarchar(100) NOT NULL, + [Description] nvarchar(2000) NULL, + CONSTRAINT [PK_Sites] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.730 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SmtpConfigurations] ( + [Id] int NOT NULL IDENTITY, + [Host] nvarchar(500) NOT NULL, + [Port] int NOT NULL, + [AuthType] nvarchar(50) NOT NULL, + [Credentials] nvarchar(4000) NULL, + [TlsMode] nvarchar(50) NULL, + [FromAddress] nvarchar(500) NOT NULL, + [ConnectionTimeoutSeconds] int NOT NULL, + [MaxConcurrentConnections] int NOT NULL, + [MaxRetries] int NOT NULL, + [RetryDelay] time NOT NULL, + CONSTRAINT [PK_SmtpConfigurations] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.732 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SystemArtifactDeploymentRecords] ( + [Id] int NOT NULL IDENTITY, + [ArtifactType] nvarchar(100) NOT NULL, + [DeployedBy] nvarchar(200) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + [PerSiteStatus] nvarchar(4000) NULL, + CONSTRAINT [PK_SystemArtifactDeploymentRecords] PRIMARY KEY ([Id]) +); +2026-03-17 02:58:03.733 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Templates] ( + [Id] int NOT NULL IDENTITY, + [Name] nvarchar(200) NOT NULL, + [Description] nvarchar(2000) NULL, + [ParentTemplateId] int NULL, + CONSTRAINT [PK_Templates] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Templates_Templates_ParentTemplateId] FOREIGN KEY ([ParentTemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION +); +2026-03-17 02:58:03.736 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [ExternalSystemMethods] ( + [Id] int NOT NULL IDENTITY, + [ExternalSystemDefinitionId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [HttpMethod] nvarchar(10) NOT NULL, + [Path] nvarchar(2000) NOT NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + CONSTRAINT [PK_ExternalSystemMethods] PRIMARY KEY ([Id]), + CONSTRAINT [FK_ExternalSystemMethods_ExternalSystemDefinitions_ExternalSystemDefinitionId] FOREIGN KEY ([ExternalSystemDefinitionId]) REFERENCES [ExternalSystemDefinitions] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.738 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [NotificationRecipients] ( + [Id] int NOT NULL IDENTITY, + [NotificationListId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [EmailAddress] nvarchar(500) NOT NULL, + CONSTRAINT [PK_NotificationRecipients] PRIMARY KEY ([Id]), + CONSTRAINT [FK_NotificationRecipients_NotificationLists_NotificationListId] FOREIGN KEY ([NotificationListId]) REFERENCES [NotificationLists] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.740 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Areas] ( + [Id] int NOT NULL IDENTITY, + [SiteId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [ParentAreaId] int NULL, + CONSTRAINT [PK_Areas] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Areas_Areas_ParentAreaId] FOREIGN KEY ([ParentAreaId]) REFERENCES [Areas] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_Areas_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.741 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SiteDataConnectionAssignments] ( + [Id] int NOT NULL IDENTITY, + [SiteId] int NOT NULL, + [DataConnectionId] int NOT NULL, + CONSTRAINT [PK_SiteDataConnectionAssignments] PRIMARY KEY ([Id]), + CONSTRAINT [FK_SiteDataConnectionAssignments_DataConnections_DataConnectionId] FOREIGN KEY ([DataConnectionId]) REFERENCES [DataConnections] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_SiteDataConnectionAssignments_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.743 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [SiteScopeRules] ( + [Id] int NOT NULL IDENTITY, + [LdapGroupMappingId] int NOT NULL, + [SiteId] int NOT NULL, + CONSTRAINT [PK_SiteScopeRules] PRIMARY KEY ([Id]), + CONSTRAINT [FK_SiteScopeRules_LdapGroupMappings_LdapGroupMappingId] FOREIGN KEY ([LdapGroupMappingId]) REFERENCES [LdapGroupMappings] ([Id]) ON DELETE CASCADE, + CONSTRAINT [FK_SiteScopeRules_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.745 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateAlarms] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [Description] nvarchar(2000) NULL, + [PriorityLevel] int NOT NULL, + [IsLocked] bit NOT NULL, + [TriggerType] nvarchar(50) NOT NULL, + [TriggerConfiguration] nvarchar(4000) NULL, + [OnTriggerScriptId] int NULL, + CONSTRAINT [PK_TemplateAlarms] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateAlarms_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.747 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateAttributes] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [Value] nvarchar(4000) NULL, + [DataType] nvarchar(50) NOT NULL, + [IsLocked] bit NOT NULL, + [Description] nvarchar(2000) NULL, + [DataSourceReference] nvarchar(500) NULL, + CONSTRAINT [PK_TemplateAttributes] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateAttributes_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.748 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateCompositions] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [ComposedTemplateId] int NOT NULL, + [InstanceName] nvarchar(200) NOT NULL, + CONSTRAINT [PK_TemplateCompositions] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateCompositions_Templates_ComposedTemplateId] FOREIGN KEY ([ComposedTemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_TemplateCompositions_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.750 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [TemplateScripts] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [Name] nvarchar(200) NOT NULL, + [IsLocked] bit NOT NULL, + [Code] nvarchar(max) NOT NULL, + [TriggerType] nvarchar(50) NULL, + [TriggerConfiguration] nvarchar(4000) NULL, + [ParameterDefinitions] nvarchar(4000) NULL, + [ReturnDefinition] nvarchar(4000) NULL, + [MinTimeBetweenRuns] time NULL, + CONSTRAINT [PK_TemplateScripts] PRIMARY KEY ([Id]), + CONSTRAINT [FK_TemplateScripts_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.753 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [Instances] ( + [Id] int NOT NULL IDENTITY, + [TemplateId] int NOT NULL, + [SiteId] int NOT NULL, + [AreaId] int NULL, + [UniqueName] nvarchar(200) NOT NULL, + [State] nvarchar(50) NOT NULL, + CONSTRAINT [PK_Instances] PRIMARY KEY ([Id]), + CONSTRAINT [FK_Instances_Areas_AreaId] FOREIGN KEY ([AreaId]) REFERENCES [Areas] ([Id]) ON DELETE SET NULL, + CONSTRAINT [FK_Instances_Sites_SiteId] FOREIGN KEY ([SiteId]) REFERENCES [Sites] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_Instances_Templates_TemplateId] FOREIGN KEY ([TemplateId]) REFERENCES [Templates] ([Id]) ON DELETE NO ACTION +); +2026-03-17 02:58:03.754 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DeployedConfigSnapshots] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [DeploymentId] nvarchar(100) NOT NULL, + [RevisionHash] nvarchar(100) NOT NULL, + [ConfigurationJson] nvarchar(max) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + CONSTRAINT [PK_DeployedConfigSnapshots] PRIMARY KEY ([Id]), + CONSTRAINT [FK_DeployedConfigSnapshots_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.756 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [DeploymentRecords] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [Status] nvarchar(50) NOT NULL, + [DeploymentId] nvarchar(100) NOT NULL, + [RevisionHash] nvarchar(100) NULL, + [DeployedBy] nvarchar(200) NOT NULL, + [DeployedAt] datetimeoffset NOT NULL, + [CompletedAt] datetimeoffset NULL, + [ErrorMessage] nvarchar(max) NULL, + [RowVersion] rowversion NOT NULL, + CONSTRAINT [PK_DeploymentRecords] PRIMARY KEY ([Id]), + CONSTRAINT [FK_DeploymentRecords_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE NO ACTION +); +2026-03-17 02:58:03.758 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [InstanceAttributeOverrides] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [AttributeName] nvarchar(200) NOT NULL, + [OverrideValue] nvarchar(4000) NULL, + CONSTRAINT [PK_InstanceAttributeOverrides] PRIMARY KEY ([Id]), + CONSTRAINT [FK_InstanceAttributeOverrides_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.759 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE TABLE [InstanceConnectionBindings] ( + [Id] int NOT NULL IDENTITY, + [InstanceId] int NOT NULL, + [AttributeName] nvarchar(200) NOT NULL, + [DataConnectionId] int NOT NULL, + CONSTRAINT [PK_InstanceConnectionBindings] PRIMARY KEY ([Id]), + CONSTRAINT [FK_InstanceConnectionBindings_DataConnections_DataConnectionId] FOREIGN KEY ([DataConnectionId]) REFERENCES [DataConnections] ([Id]) ON DELETE NO ACTION, + CONSTRAINT [FK_InstanceConnectionBindings_Instances_InstanceId] FOREIGN KEY ([InstanceId]) REFERENCES [Instances] ([Id]) ON DELETE CASCADE +); +2026-03-17 02:58:03.806 -04:00 [INF] Executed DbCommand (46ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'LdapGroupName', N'Role') AND [object_id] = OBJECT_ID(N'[LdapGroupMappings]')) + SET IDENTITY_INSERT [LdapGroupMappings] ON; +INSERT INTO [LdapGroupMappings] ([Id], [LdapGroupName], [Role]) +VALUES (1, N'SCADA-Admins', N'Admin'); +IF EXISTS (SELECT * FROM [sys].[identity_columns] WHERE [name] IN (N'Id', N'LdapGroupName', N'Role') AND [object_id] = OBJECT_ID(N'[LdapGroupMappings]')) + SET IDENTITY_INSERT [LdapGroupMappings] OFF; +2026-03-17 02:58:03.807 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiKeys_KeyValue] ON [ApiKeys] ([KeyValue]); +2026-03-17 02:58:03.808 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiKeys_Name] ON [ApiKeys] ([Name]); +2026-03-17 02:58:03.809 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ApiMethods_Name] ON [ApiMethods] ([Name]); +2026-03-17 02:58:03.810 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Areas_ParentAreaId] ON [Areas] ([ParentAreaId]); +2026-03-17 02:58:03.811 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Areas_SiteId_ParentAreaId_Name] ON [Areas] ([SiteId], [ParentAreaId], [Name]) WHERE [ParentAreaId] IS NOT NULL; +2026-03-17 02:58:03.812 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_Action] ON [AuditLogEntries] ([Action]); +2026-03-17 02:58:03.813 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_EntityId] ON [AuditLogEntries] ([EntityId]); +2026-03-17 02:58:03.814 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_EntityType] ON [AuditLogEntries] ([EntityType]); +2026-03-17 02:58:03.815 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_Timestamp] ON [AuditLogEntries] ([Timestamp]); +2026-03-17 02:58:03.816 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_AuditLogEntries_User] ON [AuditLogEntries] ([User]); +2026-03-17 02:58:03.817 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DatabaseConnectionDefinitions_Name] ON [DatabaseConnectionDefinitions] ([Name]); +2026-03-17 02:58:03.818 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DataConnections_Name] ON [DataConnections] ([Name]); +2026-03-17 02:58:03.818 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeployedConfigSnapshots_DeploymentId] ON [DeployedConfigSnapshots] ([DeploymentId]); +2026-03-17 02:58:03.819 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DeployedConfigSnapshots_InstanceId] ON [DeployedConfigSnapshots] ([InstanceId]); +2026-03-17 02:58:03.820 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeploymentRecords_DeployedAt] ON [DeploymentRecords] ([DeployedAt]); +2026-03-17 02:58:03.821 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_DeploymentRecords_DeploymentId] ON [DeploymentRecords] ([DeploymentId]); +2026-03-17 02:58:03.822 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_DeploymentRecords_InstanceId] ON [DeploymentRecords] ([InstanceId]); +2026-03-17 02:58:03.822 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ExternalSystemDefinitions_Name] ON [ExternalSystemDefinitions] ([Name]); +2026-03-17 02:58:03.823 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_ExternalSystemMethods_ExternalSystemDefinitionId_Name] ON [ExternalSystemMethods] ([ExternalSystemDefinitionId], [Name]); +2026-03-17 02:58:03.824 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_InstanceAttributeOverrides_InstanceId_AttributeName] ON [InstanceAttributeOverrides] ([InstanceId], [AttributeName]); +2026-03-17 02:58:03.825 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_InstanceConnectionBindings_DataConnectionId] ON [InstanceConnectionBindings] ([DataConnectionId]); +2026-03-17 02:58:03.826 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_InstanceConnectionBindings_InstanceId_AttributeName] ON [InstanceConnectionBindings] ([InstanceId], [AttributeName]); +2026-03-17 02:58:03.826 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Instances_AreaId] ON [Instances] ([AreaId]); +2026-03-17 02:58:03.827 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Instances_SiteId_UniqueName] ON [Instances] ([SiteId], [UniqueName]); +2026-03-17 02:58:03.828 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Instances_TemplateId] ON [Instances] ([TemplateId]); +2026-03-17 02:58:03.847 -04:00 [INF] Executed DbCommand (19ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_LdapGroupMappings_LdapGroupName] ON [LdapGroupMappings] ([LdapGroupName]); +2026-03-17 02:58:03.849 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_NotificationLists_Name] ON [NotificationLists] ([Name]); +2026-03-17 02:58:03.850 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_NotificationRecipients_NotificationListId] ON [NotificationRecipients] ([NotificationListId]); +2026-03-17 02:58:03.851 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SharedScripts_Name] ON [SharedScripts] ([Name]); +2026-03-17 02:58:03.852 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SiteDataConnectionAssignments_DataConnectionId] ON [SiteDataConnectionAssignments] ([DataConnectionId]); +2026-03-17 02:58:03.853 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SiteDataConnectionAssignments_SiteId_DataConnectionId] ON [SiteDataConnectionAssignments] ([SiteId], [DataConnectionId]); +2026-03-17 02:58:03.853 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Sites_Name] ON [Sites] ([Name]); +2026-03-17 02:58:03.854 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Sites_SiteIdentifier] ON [Sites] ([SiteIdentifier]); +2026-03-17 02:58:03.855 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_SiteScopeRules_LdapGroupMappingId_SiteId] ON [SiteScopeRules] ([LdapGroupMappingId], [SiteId]); +2026-03-17 02:58:03.855 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SiteScopeRules_SiteId] ON [SiteScopeRules] ([SiteId]); +2026-03-17 02:58:03.856 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_SystemArtifactDeploymentRecords_DeployedAt] ON [SystemArtifactDeploymentRecords] ([DeployedAt]); +2026-03-17 02:58:03.857 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateAlarms_TemplateId_Name] ON [TemplateAlarms] ([TemplateId], [Name]); +2026-03-17 02:58:03.857 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateAttributes_TemplateId_Name] ON [TemplateAttributes] ([TemplateId], [Name]); +2026-03-17 02:58:03.858 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_TemplateCompositions_ComposedTemplateId] ON [TemplateCompositions] ([ComposedTemplateId]); +2026-03-17 02:58:03.859 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateCompositions_TemplateId_InstanceName] ON [TemplateCompositions] ([TemplateId], [InstanceName]); +2026-03-17 02:58:03.859 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_Templates_Name] ON [Templates] ([Name]); +2026-03-17 02:58:03.860 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE INDEX [IX_Templates_ParentTemplateId] ON [Templates] ([ParentTemplateId]); +2026-03-17 02:58:03.861 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +CREATE UNIQUE INDEX [IX_TemplateScripts_TemplateId_Name] ON [TemplateScripts] ([TemplateId], [Name]); +2026-03-17 02:58:03.863 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion]) +VALUES (N'20260317065749_InitialSchema', N'10.0.5'); +2026-03-17 02:58:03.868 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 02:58:03.878 -04:00 [ERR] Hosting failed to start +System.InvalidOperationException: Unable to resolve service for type 'ScadaLink.HealthMonitoring.IHealthReportTransport' while attempting to activate 'ScadaLink.HealthMonitoring.HealthReportSender'. + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier) + at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) +2026-03-17 02:58:03.881 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.InvalidOperationException: Unable to resolve service for type 'ScadaLink.HealthMonitoring.IHealthReportTransport' while attempting to activate 'ScadaLink.HealthMonitoring.HealthReportSender'. + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier) + at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 118 +2026-03-17 02:58:34.416 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:58:34.864 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:58:34.869 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 02:58:34.882 -04:00 [INF] Executed DbCommand (12ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 02:58:34.924 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 02:58:34.931 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:58:34.933 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:58:34.937 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 02:58:34.940 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 02:58:34.943 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 02:58:34.948 -04:00 [ERR] Hosting failed to start +System.InvalidOperationException: Unable to resolve service for type 'ScadaLink.HealthMonitoring.IHealthReportTransport' while attempting to activate 'ScadaLink.HealthMonitoring.HealthReportSender'. + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier) + at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) +2026-03-17 02:58:34.951 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.InvalidOperationException: Unable to resolve service for type 'ScadaLink.HealthMonitoring.IHealthReportTransport' while attempting to activate 'ScadaLink.HealthMonitoring.HealthReportSender'. + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, ServiceIdentifier serviceIdentifier, Type implementationType, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateExact(ServiceDescriptor descriptor, ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain, Int32 slot) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(ServiceIdentifier serviceIdentifier, CallSiteChain callSiteChain) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier) + at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory) + at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType) + at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 118 +2026-03-17 02:59:47.387 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 02:59:47.886 -04:00 [INF] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:59:47.891 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 02:59:47.904 -04:00 [INF] Executed DbCommand (12ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 02:59:47.946 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 02:59:47.954 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 02:59:47.956 -04:00 [INF] Executed DbCommand (1ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 02:59:47.959 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 02:59:47.963 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 02:59:47.968 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 02:59:47.979 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 02:59:48.057 -04:00 [INF] Executed DbCommand (10ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 02:59:48.061 -04:00 [INF] Creating key {898faf84-8c7d-4949-a92d-3266f8a0a9c8} with creation date 2026-03-17 06:59:47Z, activation date 2026-03-17 06:59:47Z, and expiration date 2026-06-15 06:59:47Z. +2026-03-17 02:59:48.063 -04:00 [WRN] No XML encryptor configured. Key {898faf84-8c7d-4949-a92d-3266f8a0a9c8} may be persisted to storage in unencrypted form. +2026-03-17 02:59:48.143 -04:00 [INF] Executed DbCommand (32ms) [Parameters=[@p0='?' (Size = 4000), @p1='?' (Size = 4000)], CommandType='"Text"', CommandTimeout='30'] +SET IMPLICIT_TRANSACTIONS OFF; +SET NOCOUNT ON; +INSERT INTO [DataProtectionKeys] ([FriendlyName], [Xml]) +OUTPUT INSERTED.[Id] +VALUES (@p0, @p1); +2026-03-17 02:59:48.154 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 02:59:48.261 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 02:59:48.261 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 02:59:48.305 -04:00 [INF] Now listening on: http://localhost:5000 +2026-03-17 02:59:48.306 -04:00 [INF] Application started. Press Ctrl+C to shut down. +2026-03-17 02:59:48.306 -04:00 [INF] Hosting environment: Central +2026-03-17 02:59:48.306 -04:00 [INF] Content root path: /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host +2026-03-17 03:00:04.852 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/health/ready - null null +2026-03-17 03:00:04.862 -04:00 [INF] Executing endpoint 'Health checks' +2026-03-17 03:00:04.868 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:00:04.890 -04:00 [INF] Executed endpoint 'Health checks' +2026-03-17 03:00:04.890 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/health/ready - 200 null application/json 38.7835ms +2026-03-17 03:00:04.898 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/ - null null +2026-03-17 03:00:04.900 -04:00 [INF] Authorization failed. These requirements were not met: +DenyAnonymousAuthorizationRequirement: Requires an authenticated user. +2026-03-17 03:00:04.901 -04:00 [ERR] Connection id "0HNK3UB8J91U6", Request id "0HNK3UB8J91U6:00000001": An unhandled exception was thrown by the application. +System.InvalidOperationException: Unable to find the required 'IAuthenticationService' service. Please add all the required services by calling 'IServiceCollection.AddAuthentication' in the application startup code. + at Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.GetAuthenticationService(HttpContext context) + at Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.ChallengeAsync(HttpContext context) + at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.<>c__DisplayClass0_0.<g__Handle|0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) +2026-03-17 03:00:04.903 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/ - 500 0 null 5.0506ms +2026-03-17 03:00:04.911 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/login - null null +2026-03-17 03:00:04.912 -04:00 [ERR] Connection id "0HNK3UB8J91U7", Request id "0HNK3UB8J91U7:00000001": An unhandled exception was thrown by the application. +System.InvalidOperationException: Endpoint /login (/login) contains anti-forgery metadata, but a middleware was not found that supports anti-forgery. +Configure your application startup by adding app.UseAntiforgery() in the application startup code. If there are calls to app.UseRouting() and app.UseEndpoints(...), the call to app.UseAntiforgery() must go between them. Calls to app.UseAntiforgery() must be placed after calls to app.UseAuthentication() and app.UseAuthorization(). + at Microsoft.AspNetCore.Routing.EndpointMiddleware.ThrowMissingAntiforgeryMiddlewareException(Endpoint endpoint) + at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) + at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) +2026-03-17 03:00:04.912 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/login - 500 0 null 1.158ms +2026-03-17 03:00:04.919 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 32 +2026-03-17 03:00:04.919 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:00:04.975 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [l].[Id], [l].[LdapGroupName], [l].[Role] +FROM [LdapGroupMappings] AS [l] +2026-03-17 03:00:04.990 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:00:04.990 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 71.232ms +2026-03-17 03:00:29.515 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/login - null null +2026-03-17 03:00:29.515 -04:00 [ERR] Connection id "0HNK3UB8J91U9", Request id "0HNK3UB8J91U9:00000001": An unhandled exception was thrown by the application. +System.InvalidOperationException: Endpoint /login (/login) contains anti-forgery metadata, but a middleware was not found that supports anti-forgery. +Configure your application startup by adding app.UseAntiforgery() in the application startup code. If there are calls to app.UseRouting() and app.UseEndpoints(...), the call to app.UseAntiforgery() must go between them. Calls to app.UseAntiforgery() must be placed after calls to app.UseAuthentication() and app.UseAuthorization(). + at Microsoft.AspNetCore.Routing.EndpointMiddleware.ThrowMissingAntiforgeryMiddlewareException(Endpoint endpoint) + at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext) + at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application) +2026-03-17 03:00:29.516 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/login - 500 0 null 0.7265ms +2026-03-17 03:00:44.285 -04:00 [INF] Application is shutting down... +2026-03-17 03:00:44.287 -04:00 [INF] Shutting down Akka.NET actor system via CoordinatedShutdown... +2026-03-17 03:00:44.287 -04:00 [INF] Akka.NET actor system shutdown complete. +igrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 03:00:17.091 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 03:00:17.094 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 03:00:17.103 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 03:00:17.175 -04:00 [INF] Executed DbCommand (4ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:00:17.276 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 03:00:17.276 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 03:00:17.319 -04:00 [ERR] Hosting failed to start +System.IO.IOException: Failed to bind to address http://127.0.0.1:5000: address already in use. + ---> Microsoft.AspNetCore.Connections.AddressInUseException: Address already in use + ---> System.Net.Sockets.SocketException (48): Address already in use + at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName) + at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) + at System.Net.Sockets.Socket.Bind(EndPoint localEP) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<g__OnBind|0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.DefaultAddressStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.Internal.Host.b__14_1(IHostedService service, CancellationToken token) + at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation) +2026-03-17 03:00:17.324 -04:00 [ERR] BackgroundService failed +System.OperationCanceledException: The operation was canceled. + at System.Threading.PeriodicTimer.State.Signal(Boolean stopping, CancellationToken cancellationToken) + at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.DisposeAsync() + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 119 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 40 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.<>c.<b__22_1>d.MoveNext() + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrationsAsync(CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskScheduler.TryRunInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(Task task, Boolean needsProtection) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Threading.Tasks.UnwrapPromise`1.TrySetFromTask(Task task, Boolean lookForOce) + at System.Threading.Tasks.UnwrapPromise`1.ProcessInnerTask(Task task) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.ThreadPoolWorkQueue.Dispatch() + at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() + at System.Threading.Thread.StartCallback() +--- End of stack trace from previous location --- + at System.Threading.PeriodicTimer.State.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) + at ScadaLink.HealthMonitoring.CentralHealthAggregator.ExecuteAsync(CancellationToken stoppingToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.HealthMonitoring/CentralHealthAggregator.cs:line 109 + at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService) +2026-03-17 03:00:17.325 -04:00 [FTL] The HostOptions.BackgroundServiceExceptionBehavior is configured to StopHost. A BackgroundService has thrown an unhandled exception, and the IHost instance is stopping. To avoid this behavior, configure this to Ignore; however the BackgroundService will not be restarted. +System.OperationCanceledException: The operation was canceled. + at System.Threading.PeriodicTimer.State.Signal(Boolean stopping, CancellationToken cancellationToken) + at System.Threading.CancellationTokenSource.ExecuteCallbackHandlers(Boolean throwOnFirstException) + at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.DisposeAsync() + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.Internal.Host.DisposeAsync() + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 119 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at ScadaLink.ConfigurationDatabase.MigrationHelper.ApplyOrValidateMigrationsAsync(ScadaLinkDbContext dbContext, Boolean isDevelopment, CancellationToken cancellationToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.ConfigurationDatabase/MigrationHelper.cs:line 40 + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateAsync(String targetMigration, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.<>c.<b__22_1>d.MoveNext() + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.MigrateImplementationAsync(DbContext context, String targetMigration, MigrationExecutionState state, Boolean useTransaction, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrationsAsync(CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.SetExistingTaskResult(Task`1 task, TResult result) + at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.ExecutionContextCallback(Object s) + at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext(Thread threadPoolThread) + at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.MoveNext() + at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox box, Boolean allowInlining) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskScheduler.TryRunInline(Task task, Boolean taskWasPreviouslyQueued) + at System.Threading.Tasks.TaskContinuation.InlineIfPossibleOrElseQueue(Task task, Boolean needsProtection) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task`1.TrySetResult(TResult result) + at System.Threading.Tasks.UnwrapPromise`1.TrySetFromTask(Task task, Boolean lookForOce) + at System.Threading.Tasks.UnwrapPromise`1.ProcessInnerTask(Task task) + at System.Threading.Tasks.Task.RunContinuations(Object continuationObject) + at System.Threading.Tasks.Task.FinishSlow(Boolean userDelegateExecute) + at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) + at System.Threading.ThreadPoolWorkQueue.Dispatch() + at System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() + at System.Threading.Thread.StartCallback() +--- End of stack trace from previous location --- + at System.Threading.PeriodicTimer.State.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) + at ScadaLink.HealthMonitoring.CentralHealthAggregator.ExecuteAsync(CancellationToken stoppingToken) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.HealthMonitoring/CentralHealthAggregator.cs:line 109 + at Microsoft.Extensions.Hosting.Internal.Host.TryExecuteBackgroundServiceAsync(BackgroundService backgroundService) +2026-03-17 03:00:17.325 -04:00 [INF] Application is shutting down... +2026-03-17 03:00:17.325 -04:00 [FTL] ScadaLink host terminated unexpectedly +System.IO.IOException: Failed to bind to address http://127.0.0.1:5000: address already in use. + ---> Microsoft.AspNetCore.Connections.AddressInUseException: Address already in use + ---> System.Net.Sockets.SocketException (48): Address already in use + at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, Boolean disconnectOnFailure, String callerName) + at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) + at System.Net.Sockets.Socket.Bind(EndPoint localEP) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportOptions.CreateDefaultBoundListenSocket(EndPoint endpoint) + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind() + at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.TransportManager.BindAsync(EndPoint endPoint, ConnectionDelegate connectionDelegate, EndpointConfig endpointConfig, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.<>c__DisplayClass28_0`1.<g__OnBind|0>d.MoveNext() +--- End of stack trace from previous location --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + --- End of inner exception stack trace --- + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.LocalhostListenOptions.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.DefaultAddressStrategy.BindAsync(AddressBindContext context, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.BindAsync(CancellationToken cancellationToken) + at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServerImpl.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken) + at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.Internal.Host.b__14_1(IHostedService service, CancellationToken token) + at Microsoft.Extensions.Hosting.Internal.Host.ForeachService[T](IEnumerable`1 services, CancellationToken token, Boolean concurrent, Boolean abortOnFirstException, List`1 exceptions, Func`3 operation) + at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token) + at Program.
$(String[] args) in /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host/Program.cs:line 119 +2026-03-17 03:00:48.224 -04:00 [INF] Starting ScadaLink host as Central on localhost +2026-03-17 03:00:48.695 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:00:48.700 -04:00 [INF] Acquiring an exclusive lock for migration application. See https://aka.ms/efcore-docs-migrations-lock for more information if this takes too long. +2026-03-17 03:00:48.713 -04:00 [INF] Executed DbCommand (11ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_getapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session', @LockMode = 'Exclusive'; +SELECT @result +2026-03-17 03:00:48.753 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL +BEGIN + CREATE TABLE [__EFMigrationsHistory] ( + [MigrationId] nvarchar(150) NOT NULL, + [ProductVersion] nvarchar(32) NOT NULL, + CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId]) + ); +END; +2026-03-17 03:00:48.762 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:00:48.764 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT OBJECT_ID(N'[__EFMigrationsHistory]'); +2026-03-17 03:00:48.767 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [MigrationId], [ProductVersion] +FROM [__EFMigrationsHistory] +ORDER BY [MigrationId]; +2026-03-17 03:00:48.770 -04:00 [INF] No migrations were applied. The database is already up to date. +2026-03-17 03:00:48.774 -04:00 [INF] Executed DbCommand (2ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +DECLARE @result int; +EXEC @result = sp_releaseapplock @Resource = '__EFMigrationsLock', @LockOwner = 'Session'; +SELECT @result +2026-03-17 03:00:48.783 -04:00 [INF] Central health aggregator started, offline timeout 60s +2026-03-17 03:00:48.853 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [d].[Id], [d].[FriendlyName], [d].[Xml] +FROM [DataProtectionKeys] AS [d] +2026-03-17 03:00:48.952 -04:00 [INF] Akka.NET actor system 'scadalink' started. Role=Central, Roles=Central, Hostname=localhost, Port=8081, TransportHeartbeat=5s, TransportFailure=15s +2026-03-17 03:00:48.952 -04:00 [INF] Central actors registered. CentralCommunicationActor created. +2026-03-17 03:00:48.994 -04:00 [INF] Now listening on: http://localhost:5000 +2026-03-17 03:00:48.995 -04:00 [INF] Application started. Press Ctrl+C to shut down. +2026-03-17 03:00:48.995 -04:00 [INF] Hosting environment: Central +2026-03-17 03:00:48.995 -04:00 [INF] Content root path: /Users/dohertj2/Desktop/scadalink-design/src/ScadaLink.Host +2026-03-17 03:01:01.145 -04:00 [INF] Request starting HTTP/1.1 GET http://localhost:5000/health/ready - null null +2026-03-17 03:01:01.155 -04:00 [INF] Executing endpoint 'Health checks' +2026-03-17 03:01:01.182 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT 1 +2026-03-17 03:01:01.198 -04:00 [INF] Executed endpoint 'Health checks' +2026-03-17 03:01:01.199 -04:00 [INF] Request finished HTTP/1.1 GET http://localhost:5000/health/ready - 200 null application/json 54.092ms +2026-03-17 03:01:01.231 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 32 +2026-03-17 03:01:01.232 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:01:01.266 -04:00 [INF] Executed DbCommand (3ms) [Parameters=[], CommandType='"Text"', CommandTimeout='30'] +SELECT [l].[Id], [l].[LdapGroupName], [l].[Role] +FROM [LdapGroupMappings] AS [l] +2026-03-17 03:01:01.283 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:01:01.283 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 52.6345ms +2026-03-17 03:01:01.291 -04:00 [INF] Request starting HTTP/1.1 POST http://localhost:5000/auth/login - application/x-www-form-urlencoded 29 +2026-03-17 03:01:01.292 -04:00 [INF] Executing endpoint 'HTTP: POST /auth/login' +2026-03-17 03:01:01.302 -04:00 [WRN] LDAP authentication failed for user admin +LdapException: Invalid Credentials (49) Invalid Credentials +LdapException: Matched DN: +2026-03-17 03:01:01.303 -04:00 [INF] Executed endpoint 'HTTP: POST /auth/login' +2026-03-17 03:01:01.303 -04:00 [INF] Request finished HTTP/1.1 POST http://localhost:5000/auth/login - 302 0 null 11.4004ms