Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for client cert and multiple host connection string for mongo adapter #687

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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