feat: add TLS certificate hot-reload for new connections (Gap 14.3)
Add ReloadTlsCertificates(oldOpts, newOpts) returning TlsReloadResult for path-based cert comparison and validation during config hot-reload. Add 10 targeted tests covering no-change, path detection, missing file, null transitions, and success cases.
This commit is contained in:
@@ -666,7 +666,7 @@ public static class ConfigReloader
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Reloads TLS certificates from the current options and atomically swaps them
|
||||
/// into the certificate provider. New connections will use the new certificate;
|
||||
/// existing connections keep their original certificate.
|
||||
@@ -688,6 +688,54 @@ public static class ConfigReloader
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares JetStream configuration between two <see cref="NatsOptions"/> instances and
|
||||
/// returns a <see cref="JetStreamConfigChangeResult"/> describing what changed. This drives
|
||||
/// live reconfiguration of JetStream memory limits, file store limits, and domain after a
|
||||
/// hot reload without requiring a server restart.
|
||||
/// Reference: golang/nats-server/server/reload.go — jetStreamOption.Apply.
|
||||
/// </summary>
|
||||
public static JetStreamConfigChangeResult ApplyJetStreamConfigChanges(NatsOptions oldOpts, NatsOptions newOpts)
|
||||
{
|
||||
var result = new JetStreamConfigChangeResult();
|
||||
|
||||
var oldJs = oldOpts.JetStream;
|
||||
var newJs = newOpts.JetStream;
|
||||
|
||||
// Compare JetStream MaxMemoryStore (bytes)
|
||||
var oldMem = oldJs?.MaxMemoryStore ?? 0L;
|
||||
var newMem = newJs?.MaxMemoryStore ?? 0L;
|
||||
if (oldMem != newMem)
|
||||
{
|
||||
result.MaxMemoryChanged = true;
|
||||
result.OldMaxMemory = oldMem;
|
||||
result.NewMaxMemory = newMem;
|
||||
}
|
||||
|
||||
// Compare JetStream MaxFileStore (bytes)
|
||||
var oldStore = oldJs?.MaxFileStore ?? 0L;
|
||||
var newStore = newJs?.MaxFileStore ?? 0L;
|
||||
if (oldStore != newStore)
|
||||
{
|
||||
result.MaxStoreChanged = true;
|
||||
result.OldMaxStore = oldStore;
|
||||
result.NewMaxStore = newStore;
|
||||
}
|
||||
|
||||
// Compare JetStream Domain
|
||||
var oldDomain = oldJs?.Domain ?? string.Empty;
|
||||
var newDomain = newJs?.Domain ?? string.Empty;
|
||||
if (!string.Equals(oldDomain, newDomain, StringComparison.Ordinal))
|
||||
{
|
||||
result.DomainChanged = true;
|
||||
result.OldDomain = oldDomain;
|
||||
result.NewDomain = newDomain;
|
||||
}
|
||||
|
||||
result.HasChanges = result.MaxMemoryChanged || result.MaxStoreChanged || result.DomainChanged;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -806,6 +854,46 @@ public sealed class AuthChangeResult
|
||||
/// <summary>True when the Authorization token string changed.</summary>
|
||||
public bool TokenChanged { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describes what JetStream configuration changed between two <see cref="NatsOptions"/>
|
||||
/// instances. Returned by <see cref="ConfigReloader.ApplyJetStreamConfigChanges"/> and used to
|
||||
/// drive live reconfiguration of JetStream limits and domain after a hot reload.
|
||||
/// Reference: golang/nats-server/server/reload.go — jetStreamOption.Apply.
|
||||
/// </summary>
|
||||
public sealed class JetStreamConfigChangeResult
|
||||
{
|
||||
/// <summary>True when any JetStream field changed.</summary>
|
||||
public bool HasChanges { get; set; }
|
||||
|
||||
/// <summary>True when the maximum memory store limit changed.</summary>
|
||||
public bool MaxMemoryChanged { get; set; }
|
||||
|
||||
/// <summary>True when the maximum file store limit changed.</summary>
|
||||
public bool MaxStoreChanged { get; set; }
|
||||
|
||||
/// <summary>True when the JetStream domain name changed.</summary>
|
||||
public bool DomainChanged { get; set; }
|
||||
|
||||
/// <summary>Previous MaxMemoryStore value in bytes (0 = unlimited).</summary>
|
||||
public long OldMaxMemory { get; set; }
|
||||
|
||||
/// <summary>New MaxMemoryStore value in bytes (0 = unlimited).</summary>
|
||||
public long NewMaxMemory { get; set; }
|
||||
|
||||
/// <summary>Previous MaxFileStore value in bytes (0 = unlimited).</summary>
|
||||
public long OldMaxStore { get; set; }
|
||||
|
||||
/// <summary>New MaxFileStore value in bytes (0 = unlimited).</summary>
|
||||
public long NewMaxStore { get; set; }
|
||||
|
||||
/// <summary>Previous domain name (empty string when not configured).</summary>
|
||||
public string? OldDomain { get; set; }
|
||||
|
||||
/// <summary>New domain name (empty string when not configured).</summary>
|
||||
public string? NewDomain { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of a TLS certificate path comparison and validation during config hot-reload.
|
||||
/// Returned by <see cref="ConfigReloader.ReloadTlsCertificates"/>.
|
||||
|
||||
Reference in New Issue
Block a user