diff --git a/.vscode/settings.json b/.vscode/settings.json index 415e575..088f113 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -36,5 +36,34 @@ "sudoer", "typeof", "wdlp" + ], + "yaml.customTags": [ + "!And", + "!And sequence", + "!If", + "!If sequence", + "!Not", + "!Not sequence", + "!Equals", + "!Equals sequence", + "!Or", + "!Or sequence", + "!FindInMap", + "!FindInMap sequence", + "!Base64", + "!Join", + "!Join sequence", + "!Cidr", + "!Ref", + "!Sub", + "!Sub sequence", + "!GetAtt", + "!GetAZs", + "!ImportValue", + "!ImportValue sequence", + "!Select", + "!Select sequence", + "!Split", + "!Split sequence" ] } \ No newline at end of file diff --git a/Ductus.FluentDocker.MsTest/Ductus.FluentDocker.MsTest.csproj b/Ductus.FluentDocker.MsTest/Ductus.FluentDocker.MsTest.csproj index cab05c3..8fc1816 100644 --- a/Ductus.FluentDocker.MsTest/Ductus.FluentDocker.MsTest.csproj +++ b/Ductus.FluentDocker.MsTest/Ductus.FluentDocker.MsTest.csproj @@ -33,7 +33,7 @@ Documentation: https://github.com/mariotoffia/FluentDocker - + diff --git a/Ductus.FluentDocker.Tests/Ductus.FluentDocker.Tests.csproj b/Ductus.FluentDocker.Tests/Ductus.FluentDocker.Tests.csproj index ec1dc0d..d53b7a9 100644 --- a/Ductus.FluentDocker.Tests/Ductus.FluentDocker.Tests.csproj +++ b/Ductus.FluentDocker.Tests/Ductus.FluentDocker.Tests.csproj @@ -41,7 +41,7 @@ - + PreserveNewest @@ -60,6 +60,12 @@ PreserveNewest + + PreserveNewest + + + PreserveNewest + diff --git a/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs b/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs index 12a8ae5..572e441 100644 --- a/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs +++ b/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs @@ -24,13 +24,6 @@ public static void Initialize(TestContext ctx) Utilities.EnsureImage("postgres:9.6-alpine", TimeSpan.FromMinutes(1.0)); } - [TestMethod] - [TestCategory("CI")] - public void VersionInfoShallBePossibleToRetrieve() - { - var v = Fd.Version(); - Assert.IsTrue(v != null && v.Length > 0); - } [TestMethod] [TestCategory("CI")] public void BuildContainerRenderServiceInStoppedMode() @@ -500,6 +493,31 @@ public void ReuseOfExistingContainerShallWork() } } + [TestMethod] + [TestCategory("CI")] + public void DeleteIfExistsWithContainerShallWork() + { + var name = Guid.NewGuid().ToString(); + + var container = Fd.UseContainer() + .UseImage("postgres:9.6-alpine") + .WithName($"name-{name}") + .Build(); + + var id = container.Id; + + using (var c = Fd + .UseContainer() + .DeleteIfExists() + .UseImage("postgres:9.6-alpine") + .WithName($"name-{name}") + .Build()) + { + // Ids should not be equal - since deleted and then created. + AreNotEqual(id, c.Id); + } + } + [TestMethod] [TestCategory("CI")] public void PullContainerBeforeRunningShallWork() diff --git a/Ductus.FluentDocker.Tests/FluentApiTests/FluentDockerComposeTests.cs b/Ductus.FluentDocker.Tests/FluentApiTests/FluentDockerComposeTests.cs index 0be6b37..2f7fa45 100644 --- a/Ductus.FluentDocker.Tests/FluentApiTests/FluentDockerComposeTests.cs +++ b/Ductus.FluentDocker.Tests/FluentApiTests/FluentDockerComposeTests.cs @@ -335,5 +335,23 @@ public void Issue94() Assert.AreEqual("1", zookeeper.InstanceId); } } + + [TestMethod] + public void Issue190() + { + var file = Path.Combine(Directory.GetCurrentDirectory(), + (TemplateString)"Resources/hellotest/docker-compose.yml"); + + using (var svc = Fd.UseContainer() + .FromComposeFile(file) + .RemoveNonTaggedImages() + .ForceBuild() + .Build() + .Start()) + { + } + + // Now the custom build image should be removed! + } } } diff --git a/Ductus.FluentDocker.Tests/Model/Containers/ContainerTests.cs b/Ductus.FluentDocker.Tests/Model/Containers/ContainerTests.cs new file mode 100644 index 0000000..6f408cb --- /dev/null +++ b/Ductus.FluentDocker.Tests/Model/Containers/ContainerTests.cs @@ -0,0 +1,22 @@ +using Ductus.FluentDocker.Model.Common; +using Ductus.FluentDocker.Extensions; +using Ductus.FluentDocker.Model.Containers; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Newtonsoft.Json; + +namespace Ductus.FluentDocker.Tests.Model.Containers +{ + [TestClass] + public class ContainerTests + { + [TestMethod] + public void TestWithNoCreated() + { + var data = ((TemplateString)"Model/Containers/inspect_no_create.json").FromFile(); + var obj = JsonConvert.DeserializeObject(data); + + Assert.AreEqual(obj.Created, default(System.DateTime)); + } + + } +} \ No newline at end of file diff --git a/Ductus.FluentDocker.Tests/Model/Containers/inspect.json b/Ductus.FluentDocker.Tests/Model/Containers/inspect.json new file mode 100644 index 0000000..9af9287 --- /dev/null +++ b/Ductus.FluentDocker.Tests/Model/Containers/inspect.json @@ -0,0 +1,269 @@ +{ + "Id": "490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e", + "Created": "2021-08-17T06:10:47.5281411Z", + "Path": "nginx", + "Args": [ + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": true, + "Paused": false, + "Restarting": false, + "OOMKilled": false, + "Dead": false, + "Pid": 1147, + "ExitCode": 0, + "Error": "", + "StartedAt": "2021-08-17T06:10:47.9763392Z", + "FinishedAt": "0001-01-01T00:00:00Z", + "Health": { + "Status": "healthy", + "FailingStreak": 0, + "Log": [ + { + "Start": "2021-08-17T06:13:48.2680847Z", + "End": "2021-08-17T06:13:48.3372753Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:14:18.3483842Z", + "End": "2021-08-17T06:14:18.3970737Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:14:48.4063015Z", + "End": "2021-08-17T06:14:48.4489393Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:15:18.4597211Z", + "End": "2021-08-17T06:15:18.5093092Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:15:48.5184818Z", + "End": "2021-08-17T06:15:48.5734845Z", + "ExitCode": 0, + "Output": "" + } + ] + } + }, + "Image": "sha256:5dd0c746427b76deb84066cb02175d3ba20d6ca45242abe7c130edf319f29bf9", + "ResolvConfPath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/hostname", + "HostsPath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/hosts", + "LogPath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e-json.log", + "Name": "/excalidraw", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": null, + "HostConfig": { + "Binds": null, + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "default", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "5000" + } + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": true, + "VolumeDriver": "", + "VolumesFrom": null, + "CapAdd": null, + "CapDrop": null, + "CgroupnsMode": "host", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": null, + "GroupAdd": null, + "IpcMode": "private", + "Cgroup": "", + "Links": null, + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": false, + "PublishAllPorts": false, + "ReadonlyRootfs": false, + "SecurityOpt": null, + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "ConsoleSize": [ + 0, + 0 + ], + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": null, + "BlkioDeviceWriteBps": null, + "BlkioDeviceReadIOps": null, + "BlkioDeviceWriteIOps": null, + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": null, + "DeviceRequests": null, + "KernelMemory": 0, + "KernelMemoryTCP": 0, + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": null, + "OomKillDisable": false, + "PidsLimit": null, + "Ulimits": null, + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053-init/diff:/var/lib/docker/overlay2/66233c22cdf3366954300515f99c179c4e23182ade1e7a46e6c130b62b84e64f/diff:/var/lib/docker/overlay2/f547213bae92bdfd0bd904d089f7be0b8a8aff9b0512ecab444a8f74b133b077/diff:/var/lib/docker/overlay2/6b9f5edd88d7953edb06358ff5c6808312cfbfda430287156befea9298a64491/diff", + "MergedDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053/merged", + "UpperDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053/diff", + "WorkDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "490c464c0c10", + "Domainname": "", + "User": "", + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.17.10", + "NJS_VERSION=0.3.9", + "PKG_RELEASE=1" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Healthcheck": { + "Test": [ + "CMD-SHELL", + "wget -q -O /dev/null http://localhost || exit 1" + ] + }, + "Image": "excalidraw/excalidraw:latest", + "Volumes": null, + "WorkingDir": "", + "Entrypoint": null, + "OnBuild": null, + "Labels": { + "desktop.docker.io/wsl-distro": "Ubuntu-18.04", + "maintainer": "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e" + }, + "StopSignal": "SIGTERM" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "a0dbb79456d465b67e98c224ad6ffb7c63e5916a5cc5659076cc97838e20a770", + "HairpinMode": false, + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "5000" + }, + { + "HostIp": "::", + "HostPort": "5000" + } + ] + }, + "SandboxKey": "/var/run/docker/netns/a0dbb79456d4", + "SecondaryIPAddresses": null, + "SecondaryIPv6Addresses": null, + "EndpointID": "2d89f7dce00590293a13ffc1017614c09c22916537bc21be358544dc67580e88", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02:42:ac:11:00:02", + "Networks": { + "bridge": { + "IPAMConfig": null, + "Links": null, + "Aliases": null, + "NetworkID": "55f5721b918cd170cf4b610bc562ff97a29666529f59099c202de64921e13d21", + "EndpointID": "2d89f7dce00590293a13ffc1017614c09c22916537bc21be358544dc67580e88", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "MacAddress": "02:42:ac:11:00:02", + "DriverOpts": null + } + } + } +} \ No newline at end of file diff --git a/Ductus.FluentDocker.Tests/Model/Containers/inspect_no_create.json b/Ductus.FluentDocker.Tests/Model/Containers/inspect_no_create.json new file mode 100644 index 0000000..d5f2cd3 --- /dev/null +++ b/Ductus.FluentDocker.Tests/Model/Containers/inspect_no_create.json @@ -0,0 +1,268 @@ +{ + "Id": "490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e", + "Path": "nginx", + "Args": [ + "-g", + "daemon off;" + ], + "State": { + "Status": "running", + "Running": true, + "Paused": false, + "Restarting": false, + "OOMKilled": false, + "Dead": false, + "Pid": 1147, + "ExitCode": 0, + "Error": "", + "StartedAt": "2021-08-17T06:10:47.9763392Z", + "FinishedAt": "0001-01-01T00:00:00Z", + "Health": { + "Status": "healthy", + "FailingStreak": 0, + "Log": [ + { + "Start": "2021-08-17T06:13:48.2680847Z", + "End": "2021-08-17T06:13:48.3372753Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:14:18.3483842Z", + "End": "2021-08-17T06:14:18.3970737Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:14:48.4063015Z", + "End": "2021-08-17T06:14:48.4489393Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:15:18.4597211Z", + "End": "2021-08-17T06:15:18.5093092Z", + "ExitCode": 0, + "Output": "" + }, + { + "Start": "2021-08-17T06:15:48.5184818Z", + "End": "2021-08-17T06:15:48.5734845Z", + "ExitCode": 0, + "Output": "" + } + ] + } + }, + "Image": "sha256:5dd0c746427b76deb84066cb02175d3ba20d6ca45242abe7c130edf319f29bf9", + "ResolvConfPath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/resolv.conf", + "HostnamePath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/hostname", + "HostsPath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/hosts", + "LogPath": "/var/lib/docker/containers/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e/490c464c0c10754e8cb898efa3021a637b7a5db720a178c96c4bbb5c0a3ade9e-json.log", + "Name": "/excalidraw", + "RestartCount": 0, + "Driver": "overlay2", + "Platform": "linux", + "MountLabel": "", + "ProcessLabel": "", + "AppArmorProfile": "", + "ExecIDs": null, + "HostConfig": { + "Binds": null, + "ContainerIDFile": "", + "LogConfig": { + "Type": "json-file", + "Config": {} + }, + "NetworkMode": "default", + "PortBindings": { + "80/tcp": [ + { + "HostIp": "", + "HostPort": "5000" + } + ] + }, + "RestartPolicy": { + "Name": "no", + "MaximumRetryCount": 0 + }, + "AutoRemove": true, + "VolumeDriver": "", + "VolumesFrom": null, + "CapAdd": null, + "CapDrop": null, + "CgroupnsMode": "host", + "Dns": [], + "DnsOptions": [], + "DnsSearch": [], + "ExtraHosts": null, + "GroupAdd": null, + "IpcMode": "private", + "Cgroup": "", + "Links": null, + "OomScoreAdj": 0, + "PidMode": "", + "Privileged": false, + "PublishAllPorts": false, + "ReadonlyRootfs": false, + "SecurityOpt": null, + "UTSMode": "", + "UsernsMode": "", + "ShmSize": 67108864, + "Runtime": "runc", + "ConsoleSize": [ + 0, + 0 + ], + "Isolation": "", + "CpuShares": 0, + "Memory": 0, + "NanoCpus": 0, + "CgroupParent": "", + "BlkioWeight": 0, + "BlkioWeightDevice": [], + "BlkioDeviceReadBps": null, + "BlkioDeviceWriteBps": null, + "BlkioDeviceReadIOps": null, + "BlkioDeviceWriteIOps": null, + "CpuPeriod": 0, + "CpuQuota": 0, + "CpuRealtimePeriod": 0, + "CpuRealtimeRuntime": 0, + "CpusetCpus": "", + "CpusetMems": "", + "Devices": [], + "DeviceCgroupRules": null, + "DeviceRequests": null, + "KernelMemory": 0, + "KernelMemoryTCP": 0, + "MemoryReservation": 0, + "MemorySwap": 0, + "MemorySwappiness": null, + "OomKillDisable": false, + "PidsLimit": null, + "Ulimits": null, + "CpuCount": 0, + "CpuPercent": 0, + "IOMaximumIOps": 0, + "IOMaximumBandwidth": 0, + "MaskedPaths": [ + "/proc/asound", + "/proc/acpi", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/proc/scsi", + "/sys/firmware" + ], + "ReadonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + }, + "GraphDriver": { + "Data": { + "LowerDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053-init/diff:/var/lib/docker/overlay2/66233c22cdf3366954300515f99c179c4e23182ade1e7a46e6c130b62b84e64f/diff:/var/lib/docker/overlay2/f547213bae92bdfd0bd904d089f7be0b8a8aff9b0512ecab444a8f74b133b077/diff:/var/lib/docker/overlay2/6b9f5edd88d7953edb06358ff5c6808312cfbfda430287156befea9298a64491/diff", + "MergedDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053/merged", + "UpperDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053/diff", + "WorkDir": "/var/lib/docker/overlay2/453b538e633cc877d18f019ad8b0ff1ca8507e9f918ef5ea62a245f5920d2053/work" + }, + "Name": "overlay2" + }, + "Mounts": [], + "Config": { + "Hostname": "490c464c0c10", + "Domainname": "", + "User": "", + "AttachStdin": false, + "AttachStdout": false, + "AttachStderr": false, + "ExposedPorts": { + "80/tcp": {} + }, + "Tty": true, + "OpenStdin": true, + "StdinOnce": false, + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "NGINX_VERSION=1.17.10", + "NJS_VERSION=0.3.9", + "PKG_RELEASE=1" + ], + "Cmd": [ + "nginx", + "-g", + "daemon off;" + ], + "Healthcheck": { + "Test": [ + "CMD-SHELL", + "wget -q -O /dev/null http://localhost || exit 1" + ] + }, + "Image": "excalidraw/excalidraw:latest", + "Volumes": null, + "WorkingDir": "", + "Entrypoint": null, + "OnBuild": null, + "Labels": { + "desktop.docker.io/wsl-distro": "Ubuntu-18.04", + "maintainer": "NGINX Docker Maintainers \u003cdocker-maint@nginx.com\u003e" + }, + "StopSignal": "SIGTERM" + }, + "NetworkSettings": { + "Bridge": "", + "SandboxID": "a0dbb79456d465b67e98c224ad6ffb7c63e5916a5cc5659076cc97838e20a770", + "HairpinMode": false, + "LinkLocalIPv6Address": "", + "LinkLocalIPv6PrefixLen": 0, + "Ports": { + "80/tcp": [ + { + "HostIp": "0.0.0.0", + "HostPort": "5000" + }, + { + "HostIp": "::", + "HostPort": "5000" + } + ] + }, + "SandboxKey": "/var/run/docker/netns/a0dbb79456d4", + "SecondaryIPAddresses": null, + "SecondaryIPv6Addresses": null, + "EndpointID": "2d89f7dce00590293a13ffc1017614c09c22916537bc21be358544dc67580e88", + "Gateway": "172.17.0.1", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "MacAddress": "02:42:ac:11:00:02", + "Networks": { + "bridge": { + "IPAMConfig": null, + "Links": null, + "Aliases": null, + "NetworkID": "55f5721b918cd170cf4b610bc562ff97a29666529f59099c202de64921e13d21", + "EndpointID": "2d89f7dce00590293a13ffc1017614c09c22916537bc21be358544dc67580e88", + "Gateway": "172.17.0.1", + "IPAddress": "172.17.0.2", + "IPPrefixLen": 16, + "IPv6Gateway": "", + "GlobalIPv6Address": "", + "GlobalIPv6PrefixLen": 0, + "MacAddress": "02:42:ac:11:00:02", + "DriverOpts": null + } + } + } +} \ No newline at end of file diff --git a/Ductus.FluentDocker.Tests/Resources/hellotest/docker-compose.yml b/Ductus.FluentDocker.Tests/Resources/hellotest/docker-compose.yml new file mode 100644 index 0000000..9c6439e --- /dev/null +++ b/Ductus.FluentDocker.Tests/Resources/hellotest/docker-compose.yml @@ -0,0 +1,8 @@ +version: "3.4" + +services: + hellotest: + image: hellotest:v2 + build: + context: hellotest + dockerfile: Dockerfile \ No newline at end of file diff --git a/Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/Dockerfile b/Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/Dockerfile new file mode 100644 index 0000000..a49c427 --- /dev/null +++ b/Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/Dockerfile @@ -0,0 +1,3 @@ +FROM scratch +COPY hello / +CMD ["/hello"] \ No newline at end of file diff --git a/Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/hello b/Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/hello new file mode 100755 index 0000000..5052f25 Binary files /dev/null and b/Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/hello differ diff --git a/Ductus.FluentDocker/Builders/ContainerBuilder.cs b/Ductus.FluentDocker/Builders/ContainerBuilder.cs index b246860..4874dce 100644 --- a/Ductus.FluentDocker/Builders/ContainerBuilder.cs +++ b/Ductus.FluentDocker/Builders/ContainerBuilder.cs @@ -35,6 +35,19 @@ public override IContainerService Build() // Login on private repo if needed. _repositoryBuilder?.Build(host.Value); + // Destroy the container if it already exists (if enabled). + if (_config.DestroyIfExists != null && + !string.IsNullOrEmpty(_config.CreateParams.Name)) + { + host.Value.Host.RemoveContainer( + _config.CreateParams.Name, + _config.DestroyIfExists.Force, + _config.DestroyIfExists.RemoveVolumes, + _config.DestroyIfExists.LinkToRemove, + host.Value.Certificates); + + } + if (_config.VerifyExistence && !string.IsNullOrEmpty(_config.CreateParams.Name)) { // Since filter on docker is only prefix filter @@ -484,6 +497,27 @@ public ContainerBuilder ReuseIfExists() return this; } + + /// + /// This will ensure that the *named* container is deleted before the container is created. + /// + /// Optional. If set to true it will remove all volumes. True by default. + /// Optional. Fore will try to force delete the container. False by default. + /// Optional. When set to a value other than null it will remove any linkage. Null by default. + /// + public ContainerBuilder DeleteIfExists(bool removeVolumes = true, bool force = false, string removeLink = null) + { + _config.DestroyIfExists = new DestroyIfExistParams + { + Force = force, + RemoveVolumes = removeVolumes, + LinkToRemove = removeLink + }; + + + return this; + } + /// /// Uses a already pre-existing network service. It will automatically /// detach this container from the network when the network is disposed. diff --git a/Ductus.FluentDocker/Ductus.FluentDocker.csproj b/Ductus.FluentDocker/Ductus.FluentDocker.csproj index 8e6222e..12850f2 100644 --- a/Ductus.FluentDocker/Ductus.FluentDocker.csproj +++ b/Ductus.FluentDocker/Ductus.FluentDocker.csproj @@ -34,7 +34,7 @@ latest - + diff --git a/Ductus.FluentDocker/Extensions/FileExtensions.cs b/Ductus.FluentDocker/Extensions/FileExtensions.cs index ca46ec0..83955f0 100644 --- a/Ductus.FluentDocker/Extensions/FileExtensions.cs +++ b/Ductus.FluentDocker/Extensions/FileExtensions.cs @@ -1,5 +1,4 @@ -using System.Collections.Generic; -using System.IO; +using System.IO; using System.Text; using Ductus.FluentDocker.Model.Common; diff --git a/Ductus.FluentDocker/Model/Builders/ContainerBuilderConfig.cs b/Ductus.FluentDocker/Model/Builders/ContainerBuilderConfig.cs index 8386a39..9b188e7 100644 --- a/Ductus.FluentDocker/Model/Builders/ContainerBuilderConfig.cs +++ b/Ductus.FluentDocker/Model/Builders/ContainerBuilderConfig.cs @@ -8,10 +8,24 @@ namespace Ductus.FluentDocker.Model.Builders { + public sealed class DestroyIfExistParams { + public bool Force { get; set; } + public bool RemoveVolumes { get; set; } + public string LinkToRemove { get; set; } + } + public sealed class ContainerBuilderConfig { public ContainerBuilderConfig() => CreateParams = new ContainerCreateParams(); + /// + /// When set to true, the container will be removed if it exists before creating it. + /// + /// true if it shall be destroyed if exists, false if skip checking and destroy. + /// + /// Default is false. + /// + public DestroyIfExistParams DestroyIfExists { get; set; } public bool VerifyExistence { get; set; } public ContainerCreateParams CreateParams { get; } public string Image { get; set; } diff --git a/Ductus.FluentDocker/Model/Containers/Container.cs b/Ductus.FluentDocker/Model/Containers/Container.cs index c9af716..95dce0a 100644 --- a/Ductus.FluentDocker/Model/Containers/Container.cs +++ b/Ductus.FluentDocker/Model/Containers/Container.cs @@ -4,6 +4,7 @@ public sealed class Container { public string Id { get; set; } public string Image { get; set; } + public System.DateTime Created { get; set; } public string ResolvConfPath { get; set; } public string HostnamePath { get; set; } public string HostsPath { get; set; } diff --git a/Examples/.vscode/settings.json b/Examples/.vscode/settings.json new file mode 100644 index 0000000..73581e1 --- /dev/null +++ b/Examples/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "Ductus" + ] +} \ No newline at end of file diff --git a/Examples/.vscode/tasks.json b/Examples/.vscode/tasks.json new file mode 100644 index 0000000..31c32bd --- /dev/null +++ b/Examples/.vscode/tasks.json @@ -0,0 +1,24 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "shell", + "args": [ + "build", + // Ask dotnet build to generate full paths for file names. + "/property:GenerateFullPaths=true", + // Do not generate summary otherwise it leads to duplicate errors in Problems panel + "/consoleloggerparameters:NoSummary" + ], + "group": "build", + "presentation": { + "reveal": "silent" + }, + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/Examples/DockerInDockerLinux/DockerInDockerLinux.csproj b/Examples/DockerInDockerLinux/DockerInDockerLinux.csproj new file mode 100644 index 0000000..8683037 --- /dev/null +++ b/Examples/DockerInDockerLinux/DockerInDockerLinux.csproj @@ -0,0 +1,9 @@ + + + Exe + netcoreapp3.1 + + + + + \ No newline at end of file diff --git a/Examples/DockerInDockerLinux/Dockerfile b/Examples/DockerInDockerLinux/Dockerfile new file mode 100644 index 0000000..9a3c47f --- /dev/null +++ b/Examples/DockerInDockerLinux/Dockerfile @@ -0,0 +1,12 @@ +FROM mcr.microsoft.com/dotnet/sdk:3.1 + +WORKDIR /App +COPY bin/Debug/netcoreapp3.1 . + +RUN apt-get -qq update && apt-get -qq install wget +RUN wget --quiet https://download.docker.com/linux/static/stable/x86_64/docker-20.10.8.tgz && \ + tar -xzf docker-20.10.8.tgz + +RUN cp docker/* /usr/bin/ && rm -rf docker + +ENTRYPOINT ["dotnet", "DockerInDockerLinux.dll"] \ No newline at end of file diff --git a/Examples/DockerInDockerLinux/Program.cs b/Examples/DockerInDockerLinux/Program.cs new file mode 100644 index 0000000..61e3034 --- /dev/null +++ b/Examples/DockerInDockerLinux/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Linq; +using Ductus.FluentDocker.Commands; +using Ductus.FluentDocker.Services; +namespace DockerInDockerLinux +{ + class Program + { + static void Main(string[] args) + { + var hosts = new Hosts().Discover(); + + var docker = hosts.FirstOrDefault(x => x.IsNative) ?? hosts.FirstOrDefault(x => x.Name == "default"); + Console.WriteLine($"Docker host: {docker?.Host.Host}, {docker?.Host.AbsolutePath}, {docker?.Host.AbsoluteUri}"); + + var containers = docker?.GetContainers(); + Console.WriteLine(docker?.Host.Host); + Console.WriteLine($"Number of containers: {containers?.Count}"); + } + } +} diff --git a/Examples/DockerInDockerLinux/build.sh b/Examples/DockerInDockerLinux/build.sh new file mode 100755 index 0000000..a070ce7 --- /dev/null +++ b/Examples/DockerInDockerLinux/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash +## Builds the docker image +docker build -t docker-in-docker -f Dockerfile . diff --git a/Examples/DockerInDockerLinux/run.sh b/Examples/DockerInDockerLinux/run.sh new file mode 100755 index 0000000..b47fb4a --- /dev/null +++ b/Examples/DockerInDockerLinux/run.sh @@ -0,0 +1,3 @@ +#!/bin/bash +## Will execute the built docker container +docker run --rm -v /var/run/docker.sock:/var/run/docker.sock docker-in-docker \ No newline at end of file diff --git a/Examples/Examples.sln b/Examples/Examples.sln new file mode 100644 index 0000000..eb3a7ef --- /dev/null +++ b/Examples/Examples.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DockerInDockerLinux", "DockerInDockerLinux\DockerInDockerLinux.csproj", "{956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Debug|x64.ActiveCfg = Debug|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Debug|x64.Build.0 = Debug|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Debug|x86.ActiveCfg = Debug|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Debug|x86.Build.0 = Debug|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Release|Any CPU.Build.0 = Release|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Release|x64.ActiveCfg = Release|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Release|x64.Build.0 = Release|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Release|x86.ActiveCfg = Release|Any CPU + {956E68C4-C0DA-4EEB-BD4F-B19F56A1AC24}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/Examples/global.json b/Examples/global.json new file mode 100644 index 0000000..70db897 --- /dev/null +++ b/Examples/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "3.1.402" + } +} \ No newline at end of file diff --git a/appveyor.yml b/appveyor.yml index cf101a9..fc5dbb6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -34,6 +34,7 @@ before_build: - echo good_to_deploy=%good_to_deploy% build: + project: FluentDocker.sln publish_nuget: true verbosity: minimal