From 224c6a7a26a6fe6d6cdd6e08705784031bbd6794 Mon Sep 17 00:00:00 2001 From: Mario Toffia Date: Wed, 16 Jun 2021 14:16:20 +0200 Subject: [PATCH 1/5] custom build image removal test added --- .../FluentDockerComposeTests.cs | 18 ++++++++++++++++++ .../Resources/hellotest/docker-compose.yml | 8 ++++++++ .../Resources/hellotest/hellotest/Dockerfile | 3 +++ .../Resources/hellotest/hellotest/hello | Bin 0 -> 13336 bytes 4 files changed, 29 insertions(+) create mode 100644 Ductus.FluentDocker.Tests/Resources/hellotest/docker-compose.yml create mode 100644 Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/Dockerfile create mode 100755 Ductus.FluentDocker.Tests/Resources/hellotest/hellotest/hello diff --git a/Ductus.FluentDocker.Tests/FluentApiTests/FluentDockerComposeTests.cs b/Ductus.FluentDocker.Tests/FluentApiTests/FluentDockerComposeTests.cs index 1f890c3e..cd27d2dd 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/Resources/hellotest/docker-compose.yml b/Ductus.FluentDocker.Tests/Resources/hellotest/docker-compose.yml new file mode 100644 index 00000000..9c6439e4 --- /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 00000000..a49c4275 --- /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 0000000000000000000000000000000000000000..5052f25bc5c6f3f56e3795d8bee963a28b06e5b3 GIT binary patch literal 13336 zcmeHOeQX=$89z6@#&tj9iWV#};BC2T0a_<6WoxGfY;ek($)TZ1w5p*i7yA-h^+$BR zOVW)&yGx|K+`O@Wrb*L2B-kXzKhuP^(xKL^p>8_~L9|JMZlfA7+_^2;%K8bpJ(wU;I>OV(S8*PjJTq;eG+RzF?G#?5iOBpq;ahY?II| zM1|$TGH$zYUInwL!`Zavgm$SAwACmUaq94blh38MHrsYCb?wlP=OeaWAW?hb&}@^< zy0p=65vXcyw!Zd2luul`#TE;%FK{MKU6>0$$DMT?_eHsZO9|%$!KHqOfAl>qh50_~ zaADXEewgn+)fsXEy3{F)*N8C?(}y4F$G(&?j;nXvJmMkXA>bk4A>bk4A>bk4A>bk4 zA>bk4A@F~SK+lfKCst04vmy3`w6wMn4$`%DxJ1geRv;z{WjNCI(9)`7ErRgU=ehC_ zo-hyNrM8v}c2;QQ9A)p*(tSVq;IKuFcV}vtf|kDGr{)(sBPY75<T5}!u0`Lec(R?FOfvaBt(PPg2#54nm%!CvO}_w7V-*DO6U z+eFz6JyLss`i{{zX0??K0sPkKp_V)1^ZxrfHiMs_xAjw_wk+$IxB~2ayWG4kJ@a)?R(dJB8Y#b&K==J;djJhudO{)>UVzj)qEUz$jFhRl z^eDB;bn=A$AuTODN}2dtJ6M__I(Z6~XVf$$a6WlaznPjZN+Di?xNQZO(U$lOR6?d_uvP&;KCsCDe= zt=2?YTePK3|402CFS_2D-Tamjz-g=$<1LRrEA{Awq`s=$XJ6%V3mv-u z+6<7Q-@1t!6@UGMfl91D*4M>8>Zj}vy*)H}jIv6ils)RNRbYYa?F9Q9W#?no?^(5W z!$j-NO|DQvj7T2+dqv1pK>8lt&51O%QgQLc(_fAyg#Z|PfDd8y;8AZ`)aLz@7eH877%QD*#->kPhSm`zOa+v~xB z4ZsQ>B0xjzb?i~1RPft<>V1@&;$bv0Z!2@M{&^&&iDrUZ^3o}~x!jgC054bb)N8*L#9z|Up=u2mcB&QUM@~}dR>B3l%XlYp^dkeZsGWnt=XS1@FDddSfGNQ;T zs0(CJA!7w~PbNQ1k_A;&l3I3eI1uP7kYOdSsIsO&komaloNVA)*aI4c3>Bb|G4wBL z%1H4`0TKz5K2X?Ykz_WbKEJj;|9!I#Hl84J)%DTu1DZiU?;$;}wA&@2;k(xlCTp+MUzXy`)&kDbP4* zORfOr$hpA`v|cZ+LkE(S^SCquq<>J)Yaqe?a3IDqS{k}2krdxo+-`kFBf4!kC>PU# zKyMls$&rGPvaS_!xK(f~4Z(ImSw3Z_#(04CkgCkJsw)l&(wYX_rL8RueX~=AlZ9Mc zAh5Nd+Mdd|oEymkz8EW$Qe+4_nkijDs4Ja^p$vqt|- zcSgBx)19`-Mw`rCugC8}&@6|Ko5uZ}h5NgP>+N0MrH_DbOM^eY&&M$XFaB}3b~ZQ9 zyYii&!1~?%_(mSb Date: Tue, 14 Sep 2021 09:12:06 +0200 Subject: [PATCH 2/5] DeleteIfExists implementation. --- .vscode/settings.json | 29 ++ .../Ductus.FluentDocker.MsTest.csproj | 2 +- .../Ductus.FluentDocker.Tests.csproj | 8 +- .../Model/Containers/ContainerTests.cs | 22 ++ .../Model/Containers/inspect.json | 269 ++++++++++++++++++ .../Model/Containers/inspect_no_create.json | 268 +++++++++++++++++ .../Builders/ContainerBuilder.cs | 34 +++ .../Ductus.FluentDocker.csproj | 2 +- .../Extensions/FileExtensions.cs | 3 +- .../Model/Builders/ContainerBuilderConfig.cs | 14 + .../Model/Containers/Container.cs | 1 + Examples/.vscode/settings.json | 5 + Examples/.vscode/tasks.json | 24 ++ .../DockerInDockerLinux.csproj | 9 + Examples/DockerInDockerLinux/Dockerfile | 12 + Examples/DockerInDockerLinux/Program.cs | 21 ++ Examples/DockerInDockerLinux/build.sh | 3 + Examples/DockerInDockerLinux/run.sh | 3 + Examples/Examples.sln | 34 +++ Examples/global.json | 5 + 20 files changed, 763 insertions(+), 5 deletions(-) create mode 100644 Ductus.FluentDocker.Tests/Model/Containers/ContainerTests.cs create mode 100644 Ductus.FluentDocker.Tests/Model/Containers/inspect.json create mode 100644 Ductus.FluentDocker.Tests/Model/Containers/inspect_no_create.json create mode 100644 Examples/.vscode/settings.json create mode 100644 Examples/.vscode/tasks.json create mode 100644 Examples/DockerInDockerLinux/DockerInDockerLinux.csproj create mode 100644 Examples/DockerInDockerLinux/Dockerfile create mode 100644 Examples/DockerInDockerLinux/Program.cs create mode 100755 Examples/DockerInDockerLinux/build.sh create mode 100755 Examples/DockerInDockerLinux/run.sh create mode 100644 Examples/Examples.sln create mode 100644 Examples/global.json diff --git a/.vscode/settings.json b/.vscode/settings.json index 415e575c..088f113e 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 cab05c3c..8fc18161 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 ec1dc0d8..d53b7a9d 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/Model/Containers/ContainerTests.cs b/Ductus.FluentDocker.Tests/Model/Containers/ContainerTests.cs new file mode 100644 index 00000000..6f408cb8 --- /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 00000000..9af92872 --- /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 00000000..d5f2cd3e --- /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/Builders/ContainerBuilder.cs b/Ductus.FluentDocker/Builders/ContainerBuilder.cs index b246860b..4874dce7 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 8e6222ef..12850f27 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 ca46ec0c..83955f07 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 8386a396..9b188e71 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 c9af7163..95dce0ae 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 00000000..73581e1d --- /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 00000000..31c32bd3 --- /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 00000000..86830377 --- /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 00000000..9a3c47fd --- /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 00000000..61e3034e --- /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 00000000..a070ce78 --- /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 00000000..b47fb4a2 --- /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 00000000..eb3a7eff --- /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 00000000..70db8972 --- /dev/null +++ b/Examples/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "3.1.402" + } +} \ No newline at end of file From e3d3021f1f917346f942930a24f389fef4472e01 Mon Sep 17 00:00:00 2001 From: Mario Toffia Date: Tue, 14 Sep 2021 09:25:03 +0200 Subject: [PATCH 3/5] update appveyor.yml to point to FluentDocker.sln --- appveyor.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/appveyor.yml b/appveyor.yml index cf101a93..fc5dbb61 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 From 77c87ec48aeb94b25408a03a94242a45ebbcf74c Mon Sep 17 00:00:00 2001 From: Mario Toffia Date: Tue, 14 Sep 2021 09:35:34 +0200 Subject: [PATCH 4/5] unit test for DeleteIfExists --- .../FluentContainerBasicTests.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs b/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs index 12a8ae5a..e4af0633 100644 --- a/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs +++ b/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs @@ -500,6 +500,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() From 4226315db814d076f8f476c7ededc6d5eb1cf957 Mon Sep 17 00:00:00 2001 From: Mario Toffia Date: Tue, 14 Sep 2021 10:04:15 +0200 Subject: [PATCH 5/5] skip version info --- .../FluentApiTests/FluentContainerBasicTests.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs b/Ductus.FluentDocker.Tests/FluentApiTests/FluentContainerBasicTests.cs index e4af0633..572e4416 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()