private static ClusterVNode BuildNode(ClusterNodeOptions options, Func <ClusterNodeOptions> loadConfigFunc) { var quorumSize = GetQuorumSize(options.ClusterSize); var disableInternalTcpTls = options.Insecure; var disableExternalTcpTls = options.Insecure || options.DisableExternalTcpTls; var httpEndPoint = new IPEndPoint(options.ExtIp, options.HttpPort); var intTcp = disableInternalTcpTls ? new IPEndPoint(options.IntIp, options.IntTcpPort) : null; var intSecTcp = !disableInternalTcpTls ? new IPEndPoint(options.IntIp, options.IntTcpPort) : null; var extTcp = options.EnableExternalTCP && disableExternalTcpTls ? new IPEndPoint(options.ExtIp, options.ExtTcpPort) : null; var extSecTcp = options.EnableExternalTCP && !disableExternalTcpTls ? new IPEndPoint(options.ExtIp, options.ExtTcpPort) : null; var intTcpPortAdvertiseAs = disableInternalTcpTls ? options.IntTcpPortAdvertiseAs : 0; var intSecTcpPortAdvertiseAs = !disableInternalTcpTls ? options.IntTcpPortAdvertiseAs : 0; var extTcpPortAdvertiseAs = options.EnableExternalTCP && disableExternalTcpTls ? options.ExtTcpPortAdvertiseAs : 0; var extSecTcpPortAdvertiseAs = options.EnableExternalTCP && !disableExternalTcpTls ? options.ExtTcpPortAdvertiseAs : 0; var prepareCount = options.PrepareCount > quorumSize ? options.PrepareCount : quorumSize; var commitCount = options.CommitCount > quorumSize ? options.CommitCount : quorumSize; Log.Information("Quorum size set to {quorum}", prepareCount); if (options.ReadOnlyReplica && options.ClusterSize <= 1) { throw new InvalidConfigurationException( "This node cannot be configured as a Read Only Replica as these node types are only supported in a clustered configuration."); } VNodeBuilder builder; if (options.ClusterSize > 1) { builder = ClusterVNodeBuilder.AsClusterMember(options.ClusterSize); if (options.ReadOnlyReplica) { builder.EnableReadOnlyReplica(); } } else { builder = ClusterVNodeBuilder.AsSingleNode(); } builder.WithLoadConfigFunction(loadConfigFunc); if (options.MemDb) { builder = builder.RunInMemory(); } else { builder = builder.RunOnDisk(options.Db); } if (options.WriteStatsToDb) { builder = builder.WithStatsStorage(StatsStorage.StreamAndFile); } else { builder = builder.WithStatsStorage(StatsStorage.File); } builder.WithInternalTcpOn(intTcp) .WithInternalSecureTcpOn(intSecTcp) .WithExternalTcpOn(extTcp) .WithExternalSecureTcpOn(extSecTcp) .WithHttpOn(httpEndPoint) .WithWorkerThreads(options.WorkerThreads) .WithInternalHeartbeatTimeout(TimeSpan.FromMilliseconds(options.IntTcpHeartbeatTimeout)) .WithInternalHeartbeatInterval(TimeSpan.FromMilliseconds(options.IntTcpHeartbeatInterval)) .WithExternalHeartbeatTimeout(TimeSpan.FromMilliseconds(options.ExtTcpHeartbeatTimeout)) .WithExternalHeartbeatInterval(TimeSpan.FromMilliseconds(options.ExtTcpHeartbeatInterval)) .MaximumMemoryTableSizeOf(options.MaxMemTableSize) .WithHashCollisionReadLimitOf(options.HashCollisionReadLimit) .WithGossipInterval(TimeSpan.FromMilliseconds(options.GossipIntervalMs)) .WithGossipAllowedTimeDifference(TimeSpan.FromMilliseconds(options.GossipAllowedDifferenceMs)) .WithGossipTimeout(TimeSpan.FromMilliseconds(options.GossipTimeoutMs)) .WithClusterGossipPort(options.ClusterGossipPort) .WithMinFlushDelay(TimeSpan.FromMilliseconds(options.MinFlushDelayMs)) .WithPrepareTimeout(TimeSpan.FromMilliseconds(options.PrepareTimeoutMs)) .WithCommitTimeout(TimeSpan.FromMilliseconds(options.CommitTimeoutMs)) .WithWriteTimeout(TimeSpan.FromMilliseconds(options.WriteTimeoutMs)) .WithStatsPeriod(TimeSpan.FromSeconds(options.StatsPeriodSec)) .WithDeadMemberRemovalPeriod(TimeSpan.FromSeconds(options.DeadMemberRemovalPeriodSec)) .WithPrepareCount(prepareCount) .WithCommitCount(commitCount) .WithNodePriority(options.NodePriority) .WithScavengeHistoryMaxAge(options.ScavengeHistoryMaxAge) .WithIndexPath(options.Index) .WithIndexVerification(options.SkipIndexVerify) .WithIndexCacheDepth(options.IndexCacheDepth) .WithIndexMergeOptimization(options.OptimizeIndexMerge) .RunProjections(options.RunProjections, options.ProjectionThreads, options.FaultOutOfOrderProjections) .WithProjectionQueryExpirationOf(TimeSpan.FromMinutes(options.ProjectionsQueryExpiry)) .WithTfCachedChunks(options.CachedChunks) .WithTfChunksCacheSize(options.ChunksCacheSize) .AdvertiseInternalHostAs(options.IntHostAdvertiseAs) .AdvertiseExternalHostAs(options.ExtHostAdvertiseAs) .AdvertiseHostToClientAs(options.AdvertiseHostToClientAs) .AdvertiseHttpPortToClientAs(options.AdvertiseHttpPortToClientAs) .AdvertiseTcpPortToClientAs(options.AdvertiseTcpPortToClientAs) .AdvertiseHttpPortAs(options.HttpPortAdvertiseAs) .AdvertiseInternalTCPPortAs(intTcpPortAdvertiseAs) .AdvertiseExternalTCPPortAs(extTcpPortAdvertiseAs) .AdvertiseInternalSecureTCPPortAs(intSecTcpPortAdvertiseAs) .AdvertiseExternalSecureTCPPortAs(extSecTcpPortAdvertiseAs) .HavingReaderThreads(options.ReaderThreadsCount) .WithConnectionPendingSendBytesThreshold(options.ConnectionPendingSendBytesThreshold) .WithConnectionQueueSizeThreshold(options.ConnectionQueueSizeThreshold) .WithChunkInitialReaderCount(options.ChunkInitialReaderCount) .WithInitializationThreads(options.InitializationThreads) .WithMaxAutoMergeIndexLevel(options.MaxAutoMergeIndexLevel) .WithMaxTruncation(options.MaxTruncation) .WithMaxAppendSize(options.MaxAppendSize) .WithEnableAtomPubOverHTTP(options.EnableAtomPubOverHTTP) .WithStreamInfoCacheCapacity(options.StreamInfoCacheCapacity); if (options.GossipSeed.Length > 0) { builder.WithGossipSeeds(options.GossipSeed); } if (options.DiscoverViaDns) { builder.WithClusterDnsName(options.ClusterDns); } else { builder.DisableDnsDiscovery(); } if (options.GossipOnSingleNode) { builder.GossipAsSingleNode(); } if (options.EnableTrustedAuth) { builder.EnableTrustedAuth(); } if (options.StartStandardProjections) { builder.StartStandardProjections(); } if (options.DisableHTTPCaching) { builder.DisableHTTPCaching(); } if (options.DisableScavengeMerging) { builder.DisableScavengeMerging(); } if (options.LogHttpRequests) { builder.EnableLoggingOfHttpRequests(); } if (options.LogFailedAuthenticationAttempts) { builder.EnableLoggingOfFailedAuthenticationAttempts(); } if (options.EnableHistograms) { builder.EnableHistograms(); } if (options.UnsafeIgnoreHardDelete) { builder.WithUnsafeIgnoreHardDelete(); } if (options.UnsafeDisableFlushToDisk) { builder.WithUnsafeDisableFlushToDisk(); } if (options.Insecure) { if (options.DisableInternalTcpTls || options.DisableExternalTcpTls) { throw new InvalidConfigurationException($"The '{nameof(options.Insecure)}' option cannot be combined with the '{nameof(options.DisableInternalTcpTls)}' or the '{nameof(options.DisableExternalTcpTls)}' options."); } builder.DisableInternalTcpTls(); builder.DisableExternalTcpTls(); builder.DisableHttps(); } if (options.DisableExternalTcpTls) { builder.DisableExternalTcpTls(); } if (options.EnableExternalTCP) { builder.EnableExternalTCP(); } if (options.DisableAdminUi) { builder.NoAdminOnPublicInterface(); } if (options.DisableStatsOnHttp) { builder.NoStatsOnPublicInterface(); } if (options.DisableGossipOnHttp) { builder.NoGossipOnPublicInterface(); } if (options.SkipDbVerify) { builder.DoNotVerifyDbHashes(); } if (options.AlwaysKeepScavenged) { builder.AlwaysKeepScavenged(); } if (options.Unbuffered) { builder.EnableUnbuffered(); } if (options.WriteThrough) { builder.EnableWriteThrough(); } if (options.SkipIndexScanOnReads) { builder.SkipIndexScanOnReads(); } if (options.ReduceFileCachePressure) { builder.ReduceFileCachePressure(); } if (options.DisableFirstLevelHttpAuthorization) { builder.DisableFirstLevelHttpAuthorization(); } if (options.UnsafeAllowSurplusNodes) { builder.WithUnsafeAllowSurplusNodes(); } builder.WithCertificateReservedNodeCommonName(options.CertificateReservedNodeCommonName); bool requireCertificates = !options.Insecure; if (options.Insecure) { Log.Warning( "Authentication and Authorization is disabled on all TCP/HTTP interfaces. " + "It is recommended to run with Authentication and Authorization enabled in production"); Log.Warning( "TLS is disabled on all TCP/HTTP interfaces - no certificates are required to run EventStoreDB. " + "It is recommended to run with TLS enabled in production."); } else { Log.Information( "TLS is enabled on at least one TCP/HTTP interface - a certificate is required to run EventStoreDB."); } if (requireCertificates) { if (!string.IsNullOrWhiteSpace(options.CertificateStoreLocation)) { var location = CertificateLoader.GetCertificateStoreLocation(options.CertificateStoreLocation); var name = CertificateLoader.GetCertificateStoreName(options.CertificateStoreName); builder.WithServerCertificateFromStore(location, name, options.CertificateSubjectName, options.CertificateThumbprint); } else if (!string.IsNullOrWhiteSpace(options.CertificateStoreName)) { var name = CertificateLoader.GetCertificateStoreName(options.CertificateStoreName); builder.WithServerCertificateFromStore(name, options.CertificateSubjectName, options.CertificateThumbprint); } else if (options.CertificateFile.IsNotEmptyString()) { builder.WithServerCertificateFromFile( options.CertificateFile, options.CertificatePrivateKeyFile, options.CertificatePassword); } else { throw new InvalidConfigurationException( "A certificate is required unless insecure mode (--insecure) is set."); } if (!string.IsNullOrEmpty(options.TrustedRootCertificatesPath)) { builder.WithTrustedRootCertificatesPath(options.TrustedRootCertificatesPath); } else { throw new InvalidConfigurationException( $"{nameof(options.TrustedRootCertificatesPath)} must be specified unless insecure mode (--insecure) is set."); } } var authorizationConfig = String.IsNullOrEmpty(options.AuthorizationConfig) ? options.Config : options.AuthorizationConfig; var authenticationConfig = String.IsNullOrEmpty(options.AuthenticationConfig) ? options.Config : options.AuthenticationConfig; var pluginLoader = new PluginLoader(new DirectoryInfo(Locations.PluginsDirectory)); AuthenticationProviderFactory authenticationProviderFactory; AuthorizationProviderFactory authorizationProviderFactory; if (!options.Insecure) { authorizationProviderFactory = GetAuthorizationProviderFactory(options.AuthorizationType, authorizationConfig, pluginLoader); authenticationProviderFactory = GetAuthenticationProviderFactory(options.AuthenticationType, authenticationConfig, pluginLoader); } else { authorizationProviderFactory = new AuthorizationProviderFactory(components => new PassthroughAuthorizationProviderFactory()); authenticationProviderFactory = new AuthenticationProviderFactory(components => new PassthroughAuthenticationProviderFactory()); } var plugInContainer = FindPlugins(); var consumerStrategyFactories = GetPlugInConsumerStrategyFactories(plugInContainer); builder.WithAuthenticationProviderFactory(authenticationProviderFactory, options.AuthenticationType == Opts.AuthenticationTypeDefault && !options.Insecure); builder.WithAuthorizationProvider(authorizationProviderFactory); var subsystemFactories = GetPlugInSubsystemFactories(plugInContainer); foreach (var subsystemFactory in subsystemFactories) { var subsystem = subsystemFactory.Create(options.Config); builder.AddCustomSubsystem(subsystem); } return(builder.Build(options, consumerStrategyFactories)); }