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

CSHARP-4718: Enable Container and kubernetes awareness #1295

Merged
merged 6 commits into from
Apr 2, 2024

Conversation

adelinowona
Copy link
Contributor

Enables container and kubernetes awareness in the driver as specified in the MongoDB Handshake Spec .

What is the motivation for this change?

  • Allows Product to track user usage of docker and kubernetes.

@@ -176,6 +179,23 @@ name switch
_ => null,
};

BsonDocument GetContainerDocument()
{
var isExecutionContainerDocker = File.Exists("/.dockerenv");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I hesitated a little about checking for existence of a file to detect if we are in a docker container. Doing this makes us a dependent on the file system which might have potential issues related to file permissions or availability. I did some digging and found there is a environment variable called DOTNET_RUNNING_IN_CONTAINER which is set automatically by official Microsoft .Net images More info . Problem is using this environment variable relies on the .net runtime to set it which is guaranteed if users use the official .Net images for their docker containers. However, it doesn't cover cases where users don't use the official .net images or choose to manually install a .net runtime in their containers. So I think checking for the file existence is our best bet unless we want to use both strategies and let them compensate for each other?

@@ -132,6 +132,17 @@ public void CreateDriverDocument_should_return_expected_result()
result.Should().Be($"{{ name : 'mongo-csharp-driver', version : '{driverVersion}' }}");
}

[Fact]
public void CreateEnvDocument_should_return_expected_result()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using file existence as check for docker container presence means we can't really unit test it because we can't easily mock FIle.Exist as it is a static class. There is a way to bypass that but it will mean complicating the code for checking docker container presence just for the sake of testing. However, I manually tested by running a mongodb .net application in a docker container with the changes to test and the docker detection logic works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See mine comment above.

@adelinowona adelinowona marked this pull request as ready for review March 18, 2024 19:20
@adelinowona adelinowona requested a review from a team as a code owner March 18, 2024 19:20
@adelinowona adelinowona requested review from JamesKovacs and BorisDog and removed request for a team March 18, 2024 19:20
BsonDocument GetContainerDocument()
{
var isExecutionContainerDocker = File.Exists("/.dockerenv");
var isOrchestratorKubernetes = Environment.GetEnvironmentVariable("KUBERNETES_SERVICE_HOST") != null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might makes sense to use EnvironmentVariableProvider here. It might be substitutable and it will help us when we will approach task to run tests in parallel.

Copy link
Member

@sanych-sun sanych-sun Mar 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably ought to implement something similar for file system. With the same motivation: having such substitutable components could help us to isolate each test without necessarily to have file on the host machine or setting environment variables, as each such host adjustment could affect other tests.

@@ -132,6 +132,17 @@ public void CreateDriverDocument_should_return_expected_result()
result.Should().Be($"{{ name : 'mongo-csharp-driver', version : '{driverVersion}' }}");
}

[Fact]
public void CreateEnvDocument_should_return_expected_result()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See mine comment above.

@@ -176,6 +179,23 @@ name switch
_ => null,
};

BsonDocument GetContainerDocument()
{
var isExecutionContainerDocker = File.Exists("/.dockerenv");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Windows file system OK with such check? Should we wrap this with try-catch (some permissions restriction could lead to exception I suppose)?

BTW, this check looks like a Linux container detection. What about Windows containers? Should we try to detect them as well?

Copy link
Contributor

@JamesKovacs JamesKovacs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. I'm OK with the current impl or switching to our own mocks for IFileSystem and IEnvironment (or whatever we want to call it. We do need the two additional test cases noted.

As for Windows container detection, if we find a way to reliably detect Docker on Windows, then we need to create a new DRIVERS ticket and update the spec so all drivers perform the detection in the same way.

result.Should().Be($"{{ name : 'vercel', container : {{ orchestrator : 'kubernetes' }} }}");
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also verify:

  • client.env.container.runtime is set to docker when /.dockerenv is present.
  • client.env.container is not present if neither Docker nor Kubernetes is deteced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Also I think I found a reliable way to detect Docker for Windows. I will reach out the owners of the DRIVERS ticket for this work to discuss further if spec needs to be updated or if we are ok with drivers not detecting Windows containers given their low usage.

Copy link
Contributor

@JamesKovacs JamesKovacs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@sanych-sun sanych-sun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, minor changes requested.


private static void Initialize()
{
__driverDocument = new Lazy<BsonDocument>(CreateDriverDocument);
__envDocument = new Lazy<BsonDocument>(CreateEnvDocument);
__osDocument = new Lazy<BsonDocument>(CreateOSDocument);
__platformString = new Lazy<string>(GetPlatformString);
__environmentVariableProvider = new Lazy<IEnvironmentVariableProvider>(() => new EnvironmentVariableProvider());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it's Lazy? It could point to EnvironmentVariableProvider.Instance by default.


private static void Initialize()
{
__driverDocument = new Lazy<BsonDocument>(CreateDriverDocument);
__envDocument = new Lazy<BsonDocument>(CreateEnvDocument);
__osDocument = new Lazy<BsonDocument>(CreateOSDocument);
__platformString = new Lazy<string>(GetPlatformString);
__environmentVariableProvider = new Lazy<IEnvironmentVariableProvider>(() => new EnvironmentVariableProvider());
__fileSystemProvider = new Lazy<IFileSystemProvider>(() => new FileSystemProvider());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here: I suppose we do not need Lazy, just use Instance by default.

Copy link
Member

@sanych-sun sanych-sun left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@BorisDog BorisDog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, some minor comments for your consideration.
File and environment vars mocking approach is a great addition.

bool Exists(string name);
}

internal class FileWrapper : IFile
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: sealed?

internal class FileSystemProvider : IFileSystemProvider
{
private static readonly IFileSystemProvider __instance = new FileSystemProvider();
public static IFileSystemProvider Instance => __instance;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: maybe read-only property is sufficient ?
public static IFileSystemProvider Instance { get; } = new FileSystemProvider();

@@ -30,17 +31,31 @@ internal class ClientDocumentHelper
private static Lazy<BsonDocument> __envDocument;
private static Lazy<BsonDocument> __osDocument;
private static Lazy<string> __platformString;
private static IEnvironmentVariableProvider __environmentVariableProvider;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to use __environmentVariableProvider for all other variables in this file?
Follow up ticket for that? This is also pre-requisite for future tests parallelization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes a follow up is to be made.


ClientDocumentHelper.SetEnvironmentVariableProvider(environmentVariableProviderMock.Object);
ClientDocumentHelper.SetFileSystemProvider(fileSystemProviderMock.Object);
using (new DisposableEnvironmentVariable("VERCEL"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ideally we'd just use environmentVariableProviderMock for "VERCEL".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is connected to replacing uses of Environment with EnvironmentVariableProvider in ClientDocumentHelper.cs


if (isExecutionContainerDocker || isOrchestratorKubernetes)
{
return new BsonDocument
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: styling shortcut for your consideration

return new() 
{
 ....
}

@adelinowona adelinowona merged commit 5f7fc33 into mongodb:master Apr 2, 2024
1 check was pending
@adelinowona adelinowona deleted the csharp4718 branch April 2, 2024 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants