-
-
Notifications
You must be signed in to change notification settings - Fork 342
feat: Add docker compose support (#122) #1082
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
Open
nkz-soft
wants to merge
18
commits into
testcontainers:develop
Choose a base branch
from
nkz-soft:feature/support-docker-compose
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+410
−0
Open
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
eb986f4
feat: Add docker compose support (#122)
nkz-soft bee415b
Formatting fixes
nkz-soft 050a868
docker-compose command is deprecated, only support v2
nkz-soft 7c64403
Merge branch 'develop' into feature/support-docker-compose
nkz-soft c1eacca
Add support for the docker compose option
nkz-soft 93c0fea
Merge branch 'develop' into feature/support-docker-compose
HofmeisterAn bd94b0b
Merge branch 'develop' into feature/support-docker-compose
nkz-soft d7f7807
Adding support for deleting images
nkz-soft 9c85a92
Merge branch 'develop' into feature/support-docker-compose
nkz-soft aa0e770
Changes related to CPM support
nkz-soft 6f2f272
fix build
nkz-soft d09de62
code review fixes
nkz-soft bf3a56b
Merge branch 'develop' into feature/support-docker-compose
nkz-soft 1b30469
Merge branch 'develop' into feature/support-docker-compose
HofmeisterAn 18db5a9
chore: Align with project standard configuration
HofmeisterAn 1eead19
chore: Remove BOM from UTF-8 files
HofmeisterAn 90f6ccb
refactor: Reuse the the builder configuration in local mode
HofmeisterAn f1417d4
Merge pull request #1 from testcontainers/nkz-soft-feature/support-do…
nkz-soft File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| root = true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| namespace Testcontainers.DockerCompose; | ||
|
|
||
| /// <inheritdoc cref="DockerContainer" /> | ||
| internal abstract class DockerCompose : DockerContainer | ||
| { | ||
| private static readonly IList<string> AppLineArgs = new[] { "docker", "compose"}; | ||
|
|
||
| private static readonly IList<string> StartCommandLineArgs = new[] { "up", "-d" }; | ||
| private static readonly IList<string> StopCommandLineArgs = new[] { "down" }; | ||
|
|
||
| private static readonly IList<string> RemoveImagesArgs = new[] { "--rmi" }; | ||
| private static readonly IList<string> FilesArgs = new[] { "-f" }; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerCompose" /> class. | ||
| /// </summary> | ||
| protected DockerCompose(IContainerConfiguration configuration, ILogger logger) : base(configuration, logger) | ||
| { | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the runtime configuration. | ||
| /// </summary> | ||
| public DockerComposeConfiguration RuntimeConfiguration => _configuration as DockerComposeConfiguration; | ||
|
|
||
| /// <summary> | ||
| /// Builds a command line to start the docker compose | ||
| /// </summary> | ||
| public IList<string> BuildStartCommandLine() | ||
| { | ||
| return BuildConfiguration.Combine(BuildIncludeFileCommand(), StartCommandLineArgs).ToList(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Builds a command line to stop the docker compose | ||
| /// </summary> | ||
| public IList<string> BuildStopCommandLine() | ||
| { | ||
| var removeImagesArgs = RuntimeConfiguration.RemoveImages switch | ||
| { | ||
| RemoveImages.All => [RemoveImages.All.ToString().ToLower()], | ||
| RemoveImages.Local => [RemoveImages.Local.ToString().ToLower()], | ||
| _ => Array.Empty<string>(), | ||
| }; | ||
|
|
||
| var stopCommand = BuildConfiguration.Combine(BuildIncludeFileCommand(), | ||
| StopCommandLineArgs.AsEnumerable()); | ||
|
|
||
| return removeImagesArgs.Length > 0 | ||
| ? BuildConfiguration.Combine( | ||
| BuildConfiguration.Combine( | ||
| stopCommand, RemoveImagesArgs.AsEnumerable()), | ||
| removeImagesArgs) | ||
| .ToList() | ||
| : stopCommand.ToList(); | ||
| } | ||
|
|
||
| private IEnumerable<string> BuildIncludeFileCommand() | ||
| { | ||
| return BuildConfiguration.Combine( | ||
| BuildConfiguration.Combine(AppLineArgs.AsEnumerable(), FilesArgs.AsEnumerable()), | ||
| new[] { Path.GetFileName(RuntimeConfiguration.ComposeFile) }); | ||
| } | ||
| } | ||
147 changes: 147 additions & 0 deletions
147
src/Testcontainers.DockerCompose/DockerComposeBuilder.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| namespace Testcontainers.DockerCompose; | ||
|
|
||
| /// <inheritdoc cref="ContainerBuilder{TBuilderEntity, TContainerEntity, TConfigurationEntity}" /> | ||
| [PublicAPI] | ||
| public sealed class DockerComposeBuilder : ContainerBuilder<DockerComposeBuilder, DockerComposeContainer, DockerComposeConfiguration> | ||
| { | ||
| private const string NoComposeFile = "No docker compose file have been provided."; | ||
|
|
||
| //Docker Compose is included as part of this image. | ||
| public const string DockerComposeImage = "docker:24-cli"; | ||
|
|
||
| public const string DockerSocketPath = "/var/run/docker.sock"; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeBuilder" /> class. | ||
| /// </summary> | ||
| public DockerComposeBuilder() | ||
| : this(new DockerComposeConfiguration()) | ||
| { | ||
| DockerResourceConfiguration = Init().DockerResourceConfiguration; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeBuilder" /> class. | ||
| /// </summary> | ||
| /// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
| private DockerComposeBuilder(DockerComposeConfiguration resourceConfiguration) | ||
| : base(resourceConfiguration) | ||
| { | ||
| DockerResourceConfiguration = resourceConfiguration; | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override DockerComposeConfiguration DockerResourceConfiguration { get; } | ||
|
|
||
| /// <inheritdoc /> | ||
| public override DockerComposeContainer Build() | ||
| { | ||
| Validate(); | ||
|
|
||
| return new DockerComposeContainer(DockerResourceConfiguration, TestcontainersSettings.Logger); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Sets the compose file. | ||
| /// </summary> | ||
| /// <param name="composeFile">The compose file.</param> | ||
| /// <returns>A configured instance of <see cref="DockerComposeBuilder" />.</returns> | ||
| public DockerComposeBuilder WithComposeFile(string composeFile) | ||
| { | ||
| return Merge(DockerResourceConfiguration, new DockerComposeConfiguration | ||
| (composeFile: composeFile)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// If true use a local Docker Compose binary instead of a container. | ||
| /// </summary> | ||
| /// <param name="localCompose">Whether the local compose will be used.</param> | ||
| /// <returns>A configured instance of <see cref="DockerComposeBuilder" />.</returns> | ||
| public DockerComposeBuilder WithLocalCompose(bool localCompose) | ||
| { | ||
| return Merge(DockerResourceConfiguration, new DockerComposeConfiguration | ||
| (localCompose: localCompose)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Adds options to the docker-compose command, e.g. docker-compose --compatibility. | ||
| /// </summary> | ||
| /// <param name="options">Options for the docker-compose command.</param> | ||
| /// <returns>A configured instance of <see cref="DockerComposeBuilder" />.</returns> | ||
| public DockerComposeBuilder WithOptions(params string[] options) { | ||
| return Merge(DockerResourceConfiguration, new DockerComposeConfiguration | ||
| (options: options)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Remove images after containers shutdown. | ||
| /// </summary> | ||
| /// <param name="removeImages"></param> | ||
| /// <returns>A configured instance of <see cref="DockerComposeBuilder" />.</returns> | ||
| public DockerComposeBuilder WithRemoveImages(RemoveImages removeImages) { | ||
| return Merge(DockerResourceConfiguration, new DockerComposeConfiguration | ||
| (removeImages: removeImages)); | ||
| } | ||
nkz-soft marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
|
|
||
| /// <inheritdoc /> | ||
| protected override DockerComposeBuilder Init() | ||
| { | ||
| return base.Init() | ||
| .WithImage(DockerComposeImage) | ||
| .WithEntrypoint(CommonCommands.SleepInfinity) | ||
| .WithBindMount(DockerSocketPath, DockerSocketPath, AccessMode.ReadWrite) | ||
nkz-soft marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| .WithStartupCallback(ConfigureDockerComposeAsync); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override void Validate() | ||
| { | ||
| base.Validate(); | ||
|
|
||
| _ = Guard.Argument(DockerResourceConfiguration.ComposeFile, nameof(DockerResourceConfiguration.ComposeFile)) | ||
| .NotEmpty(); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override DockerComposeBuilder Clone(IResourceConfiguration<CreateContainerParameters> resourceConfiguration) | ||
| { | ||
| return Merge(DockerResourceConfiguration, new DockerComposeConfiguration(resourceConfiguration)); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override DockerComposeBuilder Clone(IContainerConfiguration resourceConfiguration) | ||
| { | ||
| return Merge(DockerResourceConfiguration, new DockerComposeConfiguration(resourceConfiguration)); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| protected override DockerComposeBuilder Merge(DockerComposeConfiguration oldValue, DockerComposeConfiguration newValue) | ||
| { | ||
| return new DockerComposeBuilder(new DockerComposeConfiguration(oldValue, newValue)); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Configures the compose container. | ||
| /// </summary> | ||
| /// <param name="container">The container.</param> | ||
| /// <param name="ct">Cancellation token.</param> | ||
| private async Task ConfigureDockerComposeAsync(IContainer container, CancellationToken ct = default) | ||
| { | ||
| if (container is DockerComposeRemote dockerComposeContainer && | ||
| !dockerComposeContainer.RuntimeConfiguration.LocalCompose ) | ||
| { | ||
| var fileInfo = new FileInfo(dockerComposeContainer.RuntimeConfiguration.ComposeFile); | ||
| if (!fileInfo.Exists) | ||
| { | ||
| throw new FileNotFoundException(NoComposeFile, fileInfo.Name); | ||
| } | ||
nkz-soft marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| await container.CopyAsync(fileInfo, ".", Unix.FileMode644, ct) | ||
| .ConfigureAwait(false); | ||
nkz-soft marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| await container.ExecAsync(dockerComposeContainer.BuildStartCommandLine(), ct) | ||
| .ConfigureAwait(false); | ||
nkz-soft marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| } | ||
88 changes: 88 additions & 0 deletions
88
src/Testcontainers.DockerCompose/DockerComposeConfiguration.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| namespace Testcontainers.DockerCompose; | ||
|
|
||
| /// <inheritdoc cref="ContainerConfiguration" /> | ||
| [PublicAPI] | ||
| public sealed class DockerComposeConfiguration : ContainerConfiguration | ||
| { | ||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeConfiguration" /> class. | ||
| /// </summary> | ||
| /// <param name="composeFile">The fully qualified path to the compose file.</param> | ||
| /// <param name="localCompose">Whether the local compose will be used.</param> | ||
| /// <param name="options">Options for the docker-compose command.</param> | ||
| /// <param name="removeImages">Options for remove images.</param> | ||
| public DockerComposeConfiguration( | ||
| string composeFile = null, | ||
| bool localCompose = false, | ||
| IEnumerable<string> options = null, | ||
| RemoveImages removeImages = RemoveImages.None) | ||
| { | ||
| ComposeFile = composeFile; | ||
| LocalCompose = localCompose; | ||
| Options = options ?? Array.Empty<string>(); | ||
| RemoveImages = removeImages; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeConfiguration" /> class. | ||
| /// </summary> | ||
| /// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
| public DockerComposeConfiguration(IResourceConfiguration<CreateContainerParameters> resourceConfiguration) | ||
| : base(resourceConfiguration) | ||
| { | ||
| // Passes the configuration upwards to the base implementations to create an updated immutable copy. | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeConfiguration" /> class. | ||
| /// </summary> | ||
| /// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
| public DockerComposeConfiguration(IContainerConfiguration resourceConfiguration) | ||
| : base(resourceConfiguration) | ||
| { | ||
| // Passes the configuration upwards to the base implementations to create an updated immutable copy. | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeConfiguration" /> class. | ||
| /// </summary> | ||
| /// <param name="resourceConfiguration">The Docker resource configuration.</param> | ||
| public DockerComposeConfiguration(DockerComposeConfiguration resourceConfiguration) | ||
| : this(new DockerComposeConfiguration(), resourceConfiguration) | ||
| { | ||
| // Passes the configuration upwards to the base implementations to create an updated immutable copy. | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeConfiguration" /> class. | ||
| /// </summary> | ||
| /// <param name="oldValue">The old Docker resource configuration.</param> | ||
| /// <param name="newValue">The new Docker resource configuration.</param> | ||
| public DockerComposeConfiguration(DockerComposeConfiguration oldValue, DockerComposeConfiguration newValue) | ||
| : base(oldValue, newValue) | ||
| { | ||
| ComposeFile = BuildConfiguration.Combine(oldValue.ComposeFile, newValue.ComposeFile); | ||
| LocalCompose = BuildConfiguration.Combine(oldValue.LocalCompose, newValue.LocalCompose); | ||
| RemoveImages = BuildConfiguration.Combine(oldValue.RemoveImages, newValue.RemoveImages); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets the path to the compose file. | ||
| /// </summary> | ||
| public string ComposeFile { get; } | ||
|
|
||
| /// <summary> | ||
| /// Indicates whether local compose is enabled. | ||
| /// </summary> | ||
| public bool LocalCompose { get; } | ||
|
|
||
| /// <summary> | ||
| /// Options for the docker-compose command. | ||
| /// </summary> | ||
| public IEnumerable<string> Options { get; } = Array.Empty<string>(); | ||
|
|
||
| /// <summary> | ||
| /// Options for remove images. | ||
| /// </summary> | ||
| public RemoveImages RemoveImages { get; } = RemoveImages.None; | ||
| } |
31 changes: 31 additions & 0 deletions
31
src/Testcontainers.DockerCompose/DockerComposeContainer.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| namespace Testcontainers.DockerCompose; | ||
|
|
||
| [PublicAPI] | ||
| public class DockerComposeContainer : DockerContainer | ||
| { | ||
| private readonly IContainer _proxyContainer; | ||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="DockerComposeContainer" /> class. | ||
| /// </summary> | ||
| /// <param name="configuration"></param> | ||
| /// <param name="logger"></param> | ||
| public DockerComposeContainer(DockerComposeConfiguration configuration, ILogger logger) : base(configuration, logger) | ||
| { | ||
| _proxyContainer = configuration.LocalCompose | ||
| ? new DockerComposeLocal(configuration, logger) | ||
| : new DockerComposeRemote(configuration, logger); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public override async Task StartAsync(CancellationToken ct = default) | ||
| { | ||
| await _proxyContainer.StartAsync(ct); | ||
| } | ||
|
|
||
| /// <inheritdoc /> | ||
| public override async Task StopAsync(CancellationToken ct = default) | ||
| { | ||
| await _proxyContainer.StopAsync(ct); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.