Skip to content

Conversation

@thomhurst
Copy link

Implements Testcontainers support for Grafana with the following features:

  • Default Grafana image: grafana/grafana:11.0.0
  • Support for custom username/password authentication
  • Anonymous access configuration
  • Ability to mount datasources, dashboards, plugins, and notifiers
  • HTTP health check wait strategy
  • Connection string generation with embedded credentials

Implements Testcontainers support for Grafana with the following features:
- Default Grafana image: grafana/grafana:11.0.0
- Support for custom username/password authentication
- Anonymous access configuration
- Ability to mount datasources, dashboards, plugins, and notifiers
- HTTP health check wait strategy
- Connection string generation with embedded credentials

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@netlify
Copy link

netlify bot commented Aug 8, 2025

Deploy Preview for testcontainers-dotnet ready!

Name Link
🔨 Latest commit c16798b
🔍 Latest deploy log https://app.netlify.com/projects/testcontainers-dotnet/deploys/68efbf5ffa06e300092720a9
😎 Deploy Preview https://deploy-preview-1509--testcontainers-dotnet.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@HofmeisterAn HofmeisterAn added module An official Testcontainers module enhancement New feature or request labels Sep 21, 2025
@HofmeisterAn HofmeisterAn force-pushed the develop branch 3 times, most recently from 4900ecd to 8fa5f1b Compare October 3, 2025 20:17
Copy link
Collaborator

@HofmeisterAn HofmeisterAn left a comment

Choose a reason for hiding this comment

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

Thanks for the PR! It looks great overall, but there are a few small things we need to fix before we can merge it.

Comment on lines +78 to +116
/// <summary>
/// Mounts a datasource configuration file.
/// </summary>
/// <param name="datasourceFilePath">The path to the datasource configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithDataSource(string datasourceFilePath)
{
return WithBindMount(datasourceFilePath, "/etc/grafana/provisioning/datasources/");
}

/// <summary>
/// Mounts a dashboard configuration file.
/// </summary>
/// <param name="dashboardFilePath">The path to the dashboard configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithDashboard(string dashboardFilePath)
{
return WithBindMount(dashboardFilePath, "/etc/grafana/provisioning/dashboards/");
}

/// <summary>
/// Mounts a plugin configuration file.
/// </summary>
/// <param name="pluginFilePath">The path to the plugin configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithPlugin(string pluginFilePath)
{
return WithBindMount(pluginFilePath, "/etc/grafana/provisioning/plugins/");
}

/// <summary>
/// Mounts a notifier configuration file.
/// </summary>
/// <param name="notifierFilePath">The path to the notifier configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithNotifier(string notifierFilePath)
{
return WithBindMount(notifierFilePath, "/etc/grafana/provisioning/notifiers/");
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Mounting a share isn't aligned with our best practices. It can make the module incompatible with remote container runtimes. Instead, we recommend using the WithResourceMapping(FileInfo, FileInfo) API, which copies the files into the container.

.WithPortBinding(GrafanaPort, true)
.WithUsername(DefaultUsername)
.WithPassword(DefaultPassword)
.WithEnvironment("GF_AUTH_ANONYMOUS_ENABLED", "false")
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
.WithEnvironment("GF_AUTH_ANONYMOUS_ENABLED", "false")
.WithAnonymousAccessDisabled()

Comment on lines +78 to +116
/// <summary>
/// Mounts a datasource configuration file.
/// </summary>
/// <param name="datasourceFilePath">The path to the datasource configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithDataSource(string datasourceFilePath)
{
return WithBindMount(datasourceFilePath, "/etc/grafana/provisioning/datasources/");
}

/// <summary>
/// Mounts a dashboard configuration file.
/// </summary>
/// <param name="dashboardFilePath">The path to the dashboard configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithDashboard(string dashboardFilePath)
{
return WithBindMount(dashboardFilePath, "/etc/grafana/provisioning/dashboards/");
}

/// <summary>
/// Mounts a plugin configuration file.
/// </summary>
/// <param name="pluginFilePath">The path to the plugin configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithPlugin(string pluginFilePath)
{
return WithBindMount(pluginFilePath, "/etc/grafana/provisioning/plugins/");
}

/// <summary>
/// Mounts a notifier configuration file.
/// </summary>
/// <param name="notifierFilePath">The path to the notifier configuration file.</param>
/// <returns>A configured instance of <see cref="GrafanaBuilder" />.</returns>
public GrafanaBuilder WithNotifier(string notifierFilePath)
{
return WithBindMount(notifierFilePath, "/etc/grafana/provisioning/notifiers/");
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

These builder APIs haven't been tested. We typically add builder APIs only for configurations that are essential to run an instance or required for specific use cases.

Comment on lines +32 to +42
public string GetConnectionString()
{
var endpoint = GetHttpEndpoint();
var username = _configuration.Username ?? GrafanaBuilder.DefaultUsername;
var password = _configuration.Password ?? GrafanaBuilder.DefaultPassword;
return new UriBuilder(endpoint)
{
UserName = username,
Password = password
}.ToString();
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the purpose of this? The tests only use the HTTP header for authentication.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request module An official Testcontainers module

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants