Skip to content

Commit

Permalink
feat: support for client cert and multiple host connection string for…
Browse files Browse the repository at this point in the history
… mongo adapter
  • Loading branch information
aneojgurhem committed Apr 4, 2024
1 parent 1297e8e commit 823efa6
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 50 deletions.
14 changes: 9 additions & 5 deletions Adaptors/MongoDB/src/Options/MongoDB.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Collections.Generic;

using JetBrains.Annotations;

using MongoDB.Driver.Core.Configuration;

// ReSharper disable InconsistentNaming

namespace ArmoniK.Core.Adapters.MongoDB.Options;
Expand All @@ -36,12 +39,12 @@ public class MongoDB

public string ReplicaSet { get; set; } = "";

public string Host { get; set; } = "";

public int Port { get; set; }
public List<string> Hosts { get; set; } = new();

public string CAFile { get; set; } = "";

public List<string> ClientCertificateFiles { get; set; } = new();

public string CredentialsPath { get; set; } = "";

public string User { get; set; } = "";
Expand All @@ -60,6 +63,7 @@ public class MongoDB

public QueueStorage QueueStorage { get; set; } = new();

public int MaxConnectionPoolSize { get; set; } = 500;
public TimeSpan ServerSelectionTimeout { get; set; } = TimeSpan.FromMinutes(2);
public int MaxConnectionPoolSize { get; set; } = 500;
public TimeSpan ServerSelectionTimeout { get; set; } = TimeSpan.FromMinutes(2);
public ConnectionStringScheme Scheme { get; set; } = ConnectionStringScheme.MongoDB;
}
57 changes: 29 additions & 28 deletions Adaptors/MongoDB/src/ServiceCollectionExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Linq;
using System.Security.Cryptography.X509Certificates;

using ArmoniK.Api.Common.Utils;
Expand All @@ -37,7 +38,6 @@
using Microsoft.Extensions.Logging;

using MongoDB.Driver;
using MongoDB.Driver.Core.Configuration;
using MongoDB.Driver.Core.Extensions.DiagnosticSources;

namespace ArmoniK.Core.Adapters.MongoDB;
Expand Down Expand Up @@ -107,13 +107,12 @@ public static IServiceCollection AddMongoClient(this IServiceCollection services
out mongoOptions);

using var _ = logger.BeginNamedScope("MongoDB configuration",
("host", mongoOptions.Host),
("port", mongoOptions.Port));
("host", mongoOptions.Hosts));

if (string.IsNullOrEmpty(mongoOptions.Host))
if (!mongoOptions.Hosts.Any())
{
throw new ArgumentOutOfRangeException(Options.MongoDB.SettingSection,
$"{nameof(Options.MongoDB.Host)} is not defined.");
$"{nameof(Options.MongoDB.Hosts)} is not defined.");
}

if (string.IsNullOrEmpty(mongoOptions.DatabaseName))
Expand Down Expand Up @@ -164,41 +163,43 @@ public static IServiceCollection AddMongoClient(this IServiceCollection services
}
}

string connectionString;
if (string.IsNullOrEmpty(mongoOptions.User) || string.IsNullOrEmpty(mongoOptions.Password))
var url = new MongoUrlBuilder
{
Servers = mongoOptions.Hosts.Select(MongoServerAddress.Parse),
};
if (!string.IsNullOrEmpty(mongoOptions.User))
{
var template = "mongodb://{0}:{1}/{2}";
connectionString = string.Format(template,
mongoOptions.Host,
mongoOptions.Port,
mongoOptions.DatabaseName);
url.Username = mongoOptions.User;
}
else

if (!string.IsNullOrEmpty(mongoOptions.Password))
{
var template = "mongodb://{0}:{1}@{2}:{3}/{4}";
connectionString = string.Format(template,
mongoOptions.User,
mongoOptions.Password,
mongoOptions.Host,
mongoOptions.Port,
mongoOptions.DatabaseName);
url.Password = mongoOptions.Password;
}

var settings = MongoClientSettings.FromUrl(new MongoUrl(connectionString));
settings.AllowInsecureTls = mongoOptions.AllowInsecureTls;
settings.UseTls = mongoOptions.Tls;
settings.DirectConnection = mongoOptions.DirectConnection;
settings.Scheme = ConnectionStringScheme.MongoDB;
settings.MaxConnectionPoolSize = mongoOptions.MaxConnectionPoolSize;
settings.ServerSelectionTimeout = mongoOptions.ServerSelectionTimeout;
settings.ReplicaSetName = mongoOptions.ReplicaSet;
url.Scheme = mongoOptions.Scheme;
url.DirectConnection = mongoOptions.DirectConnection;
url.UseTls = mongoOptions.Tls;
url.AllowInsecureTls = mongoOptions.AllowInsecureTls;
url.MaxConnectionPoolSize = mongoOptions.MaxConnectionPoolSize;
url.ReplicaSetName = mongoOptions.ReplicaSet;
url.ServerSelectionTimeout = mongoOptions.ServerSelectionTimeout;

var settings = MongoClientSettings.FromUrl(url.ToMongoUrl());
settings.ClusterConfigurator = cb =>
{
//cb.Subscribe<CommandStartedEvent>(e => logger.LogTrace("{CommandName} - {Command}",
// e.CommandName,
// e.Command.ToJson()));
cb.Subscribe(new DiagnosticsActivityEventSubscriber());
};
if (mongoOptions.ClientCertificateFiles.Any())
{
settings.SslSettings = new SslSettings
{
ClientCertificates = mongoOptions.ClientCertificateFiles.Select(s => X509Certificate2.CreateFromPemFile(s)),
};
}

var client = new MongoClient(settings);

Expand Down
54 changes: 39 additions & 15 deletions Adaptors/MongoDB/tests/InjectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

using ArmoniK.Core.Adapters.MongoDB.Options;
using ArmoniK.Core.Common.Storage;
Expand All @@ -37,6 +41,23 @@ internal class InjectionTests
[SetUp]
public void SetUp()
{
var certReq = new CertificateRequest(new X500DistinguishedName("CN=test"),
RSA.Create(2048),
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);

var cert0 = certReq.CreateSelfSigned(DateTimeOffset.UtcNow,
DateTimeOffset.Now.AddDays(10));

var path0 = Path.Combine(Path.GetTempPath(),
"file0.pem");
var path1 = Path.Combine(Path.GetTempPath(),
"file1.pem");
File.WriteAllText(path0,
cert0.ExportCertificatePem() + "\n" + cert0.GetRSAPrivateKey()!.ExportRSAPrivateKeyPem());
File.WriteAllText(path1,
cert0.ExportCertificatePem() + "\n" + cert0.GetRSAPrivateKey()!.ExportRSAPrivateKeyPem());

Dictionary<string, string?> baseConfig = new()
{
{
Expand All @@ -49,10 +70,7 @@ public void SetUp()
"Components:LeaseProvider", "ArmoniK.Adapters.MongoDB.LeaseProvider"
},
{
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.Host)}", "localhost"
},
{
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.Port)}", "3232"
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.Hosts)}:0", "localhost:3232"
},
{
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.Tls)}", "true"
Expand Down Expand Up @@ -90,6 +108,12 @@ public void SetUp()
{
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.ObjectStorage)}:ChunkSize", "100000"
},
{
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.ClientCertificateFiles)}:0", path0
},
{
$"{Options.MongoDB.SettingSection}:{nameof(Options.MongoDB.ClientCertificateFiles)}:1", path1
},
};

var logger = NullLogger.Instance;
Expand Down Expand Up @@ -132,8 +156,17 @@ public void ReadMongoDbHost()
{
var options = provider_!.GetRequiredService<Options.MongoDB>();

Assert.AreEqual("localhost",
options.Host);
Assert.AreEqual("localhost:3232",
options.Hosts.Single());
}

[Test]
public void ReadClientCertificateFiles()
{
var options = provider_!.GetRequiredService<Options.MongoDB>();

Assert.AreEqual(2,
options.ClientCertificateFiles.Count);
}

[Test]
Expand Down Expand Up @@ -172,15 +205,6 @@ public void ReadMongoDbCaFile()
options.CAFile);
}

[Test]
public void ReadMongoDbPort()
{
var options = provider_!.GetRequiredService<Options.MongoDB>();

Assert.AreEqual(3232,
options.Port);
}

[Test]
public void ReadMongoDbTls()
{
Expand Down
3 changes: 1 addition & 2 deletions terraform/modules/storage/database/mongo/outputs.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
output "generated_env_vars" {
value = {
"Components__TableStorage" = "ArmoniK.Adapters.MongoDB.TableStorage"
"MongoDB__Host" = docker_container.database.name
"MongoDB__Port" = "${var.mongodb_params.exposed_port}"
"MongoDB__Hosts__0" = "${docker_container.database.name}:${var.mongodb_params.exposed_port}"
"MongoDB__DatabaseName" = docker_container.database.name
"MongoDB__MaxConnectionPoolSize" = "${var.mongodb_params.max_connection_pool_size}"
"MongoDB__TableStorage__PollingDelayMin" = "${var.mongodb_params.min_polling_delay}"
Expand Down

0 comments on commit 823efa6

Please sign in to comment.