build(deps): bump github.com/testcontainers/testcontainers-go/modules/opensearch

Bumps [github.com/testcontainers/testcontainers-go/modules/opensearch](https://github.com/testcontainers/testcontainers-go) from 0.41.0 to 0.42.0.
- [Release notes](https://github.com/testcontainers/testcontainers-go/releases)
- [Commits](https://github.com/testcontainers/testcontainers-go/compare/v0.41.0...v0.42.0)

---
updated-dependencies:
- dependency-name: github.com/testcontainers/testcontainers-go/modules/opensearch
  dependency-version: 0.42.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2026-04-21 14:45:40 +00:00
committed by Ralf Haferkamp
parent 68b356292b
commit d88bd1aa59
445 changed files with 11220 additions and 26099 deletions

14
go.mod
View File

@@ -83,8 +83,8 @@ require (
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
github.com/test-go/testify v1.1.4
github.com/testcontainers/testcontainers-go v0.41.0
github.com/testcontainers/testcontainers-go/modules/opensearch v0.41.0
github.com/testcontainers/testcontainers-go v0.42.0
github.com/testcontainers/testcontainers-go/modules/opensearch v0.42.0
github.com/theckman/yacspin v0.13.12
github.com/thejerf/suture/v4 v4.0.6
github.com/tidwall/gjson v1.18.0
@@ -190,7 +190,6 @@ require (
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/docker/docker v28.5.2+incompatible // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
@@ -294,14 +293,15 @@ require (
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.2.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/moby/api v1.54.1 // indirect
github.com/moby/moby/client v0.4.0 // indirect
github.com/moby/patternmatcher v0.6.1 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nats-io/jwt/v2 v2.8.1 // indirect
@@ -347,14 +347,14 @@ require (
github.com/sethvargo/go-diceware v0.5.0 // indirect
github.com/sethvargo/go-password v0.3.1 // indirect
github.com/shamaton/msgpack/v2 v2.4.0 // indirect
github.com/shirou/gopsutil/v4 v4.26.2 // indirect
github.com/shirou/gopsutil/v4 v4.26.3 // indirect
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c // indirect
github.com/shurcooL/vfsgen v0.0.0-20230704071429-0000e147ea92 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
github.com/spacewander/go-suffix-tree v0.0.0-20191010040751-0865e368c784 // indirect
github.com/spf13/cast v1.10.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/stretchr/objx v0.5.3 // indirect
github.com/studio-b12/gowebdav v0.9.0 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
github.com/tchap/go-patricia/v2 v2.3.3 // indirect

38
go.sum
View File

@@ -258,8 +258,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/cpuguy83/go-md2man/v2 v2.0.7 h1:zbFlGlXEAKlwXpmvle3d8Oe3YnkKIK4xSRTd3sHPnBo=
github.com/cpuguy83/go-md2man/v2 v2.0.7/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
github.com/crewjam/httperr v0.2.0 h1:b2BfXR8U3AlIHwNeFFvZ+BV1LFvKLlzMjzaTnZMybNo=
github.com/crewjam/httperr v0.2.0/go.mod h1:Jlz+Sg/XqBQhyMjdDiC+GNNRzZTD7x39Gu3pglZ5oH4=
github.com/crewjam/saml v0.4.14 h1:g9FBNx62osKusnFzs3QTN5L9CVA/Egfgm+stJShzw/c=
@@ -305,8 +305,6 @@ github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
github.com/dnsimple/dnsimple-go v0.63.0/go.mod h1:O5TJ0/U6r7AfT8niYNlmohpLbCSG+c71tQlGr9SeGrg=
github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM=
github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -869,10 +867,12 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.2.0 h1:zg5QDUM2mi0JIM9fdQZWC7U8+2ZfixfTYoHL7rWUcP8=
github.com/moby/go-archive v0.2.0/go.mod h1:mNeivT14o8xU+5q1YnNrkQVpK+dnNe/K6fHqnTg4qPU=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/moby/api v1.54.1 h1:TqVzuJkOLsgLDDwNLmYqACUuTehOHRGKiPhvH8V3Nn4=
github.com/moby/moby/api v1.54.1/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs=
github.com/moby/moby/client v0.4.0 h1:S+2XegzHQrrvTCvF6s5HFzcrywWQmuVnhOXe2kiWjIw=
github.com/moby/moby/client v0.4.0/go.mod h1:QWPbvWchQbxBNdaLSpoKpCdf5E+WxFAgNHogCWDoa7g=
github.com/moby/patternmatcher v0.6.1 h1:qlhtafmr6kgMIJjKJMDmMWq7WLkKIo23hsrpR3x084U=
github.com/moby/patternmatcher v0.6.1/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
@@ -891,8 +891,6 @@ github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFd
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
@@ -1116,8 +1114,8 @@ github.com/shamaton/msgpack/v2 v2.4.0 h1:O5Z08MRmbo0lA9o2xnQ4TXx6teJbPqEurqcCOQ8
github.com/shamaton/msgpack/v2 v2.4.0/go.mod h1:6khjYnkx73f7VQU7wjcFS9DFjs+59naVWJv1TB7qdOI=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil/v4 v4.26.2 h1:X8i6sicvUFih4BmYIGT1m2wwgw2VG9YgrDTi7cIRGUI=
github.com/shirou/gopsutil/v4 v4.26.2/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shirou/gopsutil/v4 v4.26.3 h1:2ESdQt90yU3oXF/CdOlRCJxrP+Am1aBYubTMTfxJ1qc=
github.com/shirou/gopsutil/v4 v4.26.3/go.mod h1:LZ6ewCSkBqUpvSOf+LsTGnRinC6iaNUNMGBtDkJBaLQ=
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c h1:aqg5Vm5dwtvL+YgDpBcK1ITf3o96N/K7/wsRXQnUTEs=
github.com/shurcooL/httpfs v0.0.0-20230704072500-f1e31cf0ba5c/go.mod h1:owqhoLW1qZoYLZzLnBw+QkPP9WZnjlSWihhxAJC1+/M=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
@@ -1171,8 +1169,8 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/objx v0.5.3 h1:jmXUvGomnU1o3W/V5h2VEradbpJDwGrzugQQvL0POH4=
github.com/stretchr/objx v0.5.3/go.mod h1:rDQraq+vQZU7Fde9LOZLr8Tax6zZvy4kuNKF+QYS+U0=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -1193,10 +1191,10 @@ github.com/tchap/go-patricia/v2 v2.3.3 h1:xfNEsODumaEcCcY3gI0hYPZ/PcpVv5ju6RMAhg
github.com/tchap/go-patricia/v2 v2.3.3/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
github.com/testcontainers/testcontainers-go v0.41.0 h1:mfpsD0D36YgkxGj2LrIyxuwQ9i2wCKAD+ESsYM1wais=
github.com/testcontainers/testcontainers-go v0.41.0/go.mod h1:pdFrEIfaPl24zmBjerWTTYaY0M6UHsqA1YSvsoU40MI=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.41.0 h1:xOHzMTJXgw/CQsrtemxLGDZGCSQg/AlaotVv273qC60=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.41.0/go.mod h1:vjKGTfDelOkOAzsFmf5YglHPnhyoHjPyDs9Z4Ane2xg=
github.com/testcontainers/testcontainers-go v0.42.0 h1:He3IhTzTZOygSXLJPMX7n44XtK+qhjat1nI9cneBbUY=
github.com/testcontainers/testcontainers-go v0.42.0/go.mod h1:vZjdY1YmUA1qEForxOIOazfsrdyORJAbhi0bp8plN30=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.42.0 h1:lXPr5NypYR0O8qcej+JQfsQTOTc3CRv+c4wz3VbBFLI=
github.com/testcontainers/testcontainers-go/modules/opensearch v0.42.0/go.mod h1:KJ+m9onB785g9VDRDuhvUvsbkRjnFp3Uz+CHoHpPieA=
github.com/thanhpk/randstr v1.0.6 h1:psAOktJFD4vV9NEVb3qkhRSMvYh4ORRaj1+w/hn4B+o=
github.com/thanhpk/randstr v1.0.6/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U=
github.com/theckman/yacspin v0.13.12 h1:CdZ57+n0U6JMuh2xqjnjRq5Haj6v1ner2djtLQRzJr4=
@@ -1310,8 +1308,6 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bT
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0 h1:RAE+JPfvEmvy+0LzyUA25/SGawPwIUbZ6u0Wug54sLc=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0 h1:inYW9ZhgqiDqh6BioM7DVHHzEGVq76Db5897WLGZ5Go=
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.41.0/go.mod h1:Izur+Wt8gClgMJqO/cZ8wdeeMryJ/xxiOVgFSSfpDTY=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0 h1:s/1iRkCKDfhlh1JF26knRneorus8aOwVIDhvYx9WoDw=
go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.42.0/go.mod h1:UI3wi0FXg1Pofb8ZBiBLhtMzgoTm1TYkMvn71fAqDzs=
go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM=
@@ -1800,6 +1796,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk=
pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

2496
vendor/github.com/docker/docker/AUTHORS generated vendored
View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,19 +0,0 @@
Docker
Copyright 2012-2017 Docker, Inc.
This product includes software developed at Docker, Inc. (https://www.docker.com).
This product contains software (https://github.com/creack/pty) developed
by Keith Rarick, licensed under the MIT License.
The following is courtesy of our legal counsel:
Use and transfer of Docker may be subject to certain restrictions by the
United States and other governments.
It is your responsibility to ensure that your use and/or transfer does not
violate applicable laws.
For more information, please see https://www.bis.doc.gov
See also https://www.apache.org/dev/crypto.html and/or seek legal counsel.

View File

@@ -1,42 +0,0 @@
# Working on the Engine API
The Engine API is an HTTP API used by the command-line client to communicate with the daemon. It can also be used by third-party software to control the daemon.
It consists of various components in this repository:
- `api/swagger.yaml` A Swagger definition of the API.
- `api/types/` Types shared by both the client and server, representing various objects, options, responses, etc. Most are written manually, but some are automatically generated from the Swagger definition. See [#27919](https://github.com/docker/docker/issues/27919) for progress on this.
- `cli/` The command-line client.
- `client/` The Go client used by the command-line client. It can also be used by third-party Go programs.
- `daemon/` The daemon, which serves the API.
## Swagger definition
The API is defined by the [Swagger](http://swagger.io/specification/) definition in `api/swagger.yaml`. This definition can be used to:
1. Automatically generate documentation.
2. Automatically generate the Go server and client. (A work-in-progress.)
3. Provide a machine readable version of the API for introspecting what it can do, automatically generating clients for other languages, etc.
## Updating the API documentation
The API documentation is generated entirely from `api/swagger.yaml`. If you make updates to the API, edit this file to represent the change in the documentation.
The file is split into two main sections:
- `definitions`, which defines re-usable objects used in requests and responses
- `paths`, which defines the API endpoints (and some inline objects which don't need to be reusable)
To make an edit, first look for the endpoint you want to edit under `paths`, then make the required edits. Endpoints may reference reusable objects with `$ref`, which can be found in the `definitions` section.
There is hopefully enough example material in the file for you to copy a similar pattern from elsewhere in the file (e.g. adding new fields or endpoints), but for the full reference, see the [Swagger specification](https://github.com/docker/docker/issues/27919).
`swagger.yaml` is validated by `hack/validate/swagger` to ensure it is a valid Swagger definition. This is useful when making edits to ensure you are doing the right thing.
## Viewing the API documentation
When you make edits to `swagger.yaml`, you may want to check the generated API documentation to ensure it renders correctly.
Run `make swagger-docs` and a preview will be running at `http://localhost:9000`. Some of the styling may be incorrect, but you'll be able to ensure that it is generating the correct documentation.
The production documentation is generated by vendoring `swagger.yaml` into [docker/docker.github.io](https://github.com/docker/docker.github.io).

View File

@@ -1,20 +0,0 @@
package api
// Common constants for daemon and client.
const (
// DefaultVersion of the current REST API.
DefaultVersion = "1.51"
// MinSupportedAPIVersion is the minimum API version that can be supported
// by the API server, specified as "major.minor". Note that the daemon
// may be configured with a different minimum API version, as returned
// in [github.com/docker/docker/api/types.Version.MinAPIVersion].
//
// API requests for API versions lower than the configured version produce
// an error.
MinSupportedAPIVersion = "1.24"
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
NoBaseImageSpecifier = "scratch"
)

View File

@@ -1,12 +0,0 @@
layout:
models:
- name: definition
source: asset:model
target: "{{ joinFilePath .Target .ModelPackage }}"
file_name: "{{ (snakize (pascalize .Name)) }}.go"
operations:
- name: handler
source: asset:serverOperation
target: "{{ joinFilePath .Target .APIPackage .Package }}"
file_name: "{{ (snakize (pascalize .Name)) }}.go"

View File

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +0,0 @@
package build
// CacheDiskUsage contains disk usage for the build cache.
//
// Deprecated: this type is no longer used and will be removed in the next release.
type CacheDiskUsage struct {
TotalSize int64
Reclaimable int64
Items []*CacheRecord
}

View File

@@ -1,19 +0,0 @@
package checkpoint
// CreateOptions holds parameters to create a checkpoint from a container.
type CreateOptions struct {
CheckpointID string
CheckpointDir string
Exit bool
}
// ListOptions holds parameters to list checkpoints for a container.
type ListOptions struct {
CheckpointDir string
}
// DeleteOptions holds parameters to delete a checkpoint from a container.
type DeleteOptions struct {
CheckpointID string
CheckpointDir string
}

View File

@@ -1,85 +0,0 @@
package types
import (
"bufio"
"context"
"net"
)
// NewHijackedResponse initializes a [HijackedResponse] type.
func NewHijackedResponse(conn net.Conn, mediaType string) HijackedResponse {
return HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn), mediaType: mediaType}
}
// HijackedResponse holds connection information for a hijacked request.
type HijackedResponse struct {
mediaType string
Conn net.Conn
Reader *bufio.Reader
}
// Close closes the hijacked connection and reader.
func (h *HijackedResponse) Close() {
h.Conn.Close()
}
// MediaType let client know if HijackedResponse hold a raw or multiplexed stream.
// returns false if HTTP Content-Type is not relevant, and container must be inspected
func (h *HijackedResponse) MediaType() (string, bool) {
if h.mediaType == "" {
return "", false
}
return h.mediaType, true
}
// CloseWriter is an interface that implements structs
// that close input streams to prevent from writing.
type CloseWriter interface {
CloseWrite() error
}
// CloseWrite closes a readWriter for writing.
func (h *HijackedResponse) CloseWrite() error {
if conn, ok := h.Conn.(CloseWriter); ok {
return conn.CloseWrite()
}
return nil
}
// PluginRemoveOptions holds parameters to remove plugins.
type PluginRemoveOptions struct {
Force bool
}
// PluginEnableOptions holds parameters to enable plugins.
type PluginEnableOptions struct {
Timeout int
}
// PluginDisableOptions holds parameters to disable plugins.
type PluginDisableOptions struct {
Force bool
}
// PluginInstallOptions holds parameters to install a plugin.
type PluginInstallOptions struct {
Disabled bool
AcceptAllPermissions bool
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
RemoteRef string // RemoteRef is the plugin name on the registry
// PrivilegeFunc is a function that clients can supply to retry operations
// after getting an authorization error. This function returns the registry
// authentication header value in base64 encoded format, or an error if the
// privilege request fails.
//
// For details, refer to [github.com/docker/docker/api/types/registry.RequestAuthConfig].
PrivilegeFunc func(context.Context) (string, error)
AcceptPermissionsFunc func(context.Context, PluginPrivileges) (bool, error)
Args []string
}
// PluginCreateOptions hold all options to plugin create.
type PluginCreateOptions struct {
RepoName string
}

View File

@@ -1,10 +0,0 @@
package container
// DiskUsage contains disk usage for containers.
//
// Deprecated: this type is no longer used and will be removed in the next release.
type DiskUsage struct {
TotalSize int64
Reclaimable int64
Items []*Summary
}

View File

@@ -1,53 +0,0 @@
package container
import "github.com/docker/docker/api/types/common"
// ExecCreateResponse is the response for a successful exec-create request.
// It holds the ID of the exec that was created.
//
// TODO(thaJeztah): make this a distinct type.
type ExecCreateResponse = common.IDResponse
// ExecOptions is a small subset of the Config struct that holds the configuration
// for the exec feature of docker.
type ExecOptions struct {
User string // User that will run the command
Privileged bool // Is the container in privileged mode
Tty bool // Attach standard streams to a tty.
ConsoleSize *[2]uint `json:",omitempty"` // Initial console size [height, width]
AttachStdin bool // Attach the standard input, makes possible user interaction
AttachStderr bool // Attach the standard error
AttachStdout bool // Attach the standard output
DetachKeys string // Escape keys for detach
Env []string // Environment variables
WorkingDir string // Working directory
Cmd []string // Execution commands and args
// Deprecated: the Detach field is not used, and will be removed in a future release.
Detach bool
}
// ExecStartOptions is a temp struct used by execStart
// Config fields is part of ExecConfig in runconfig package
type ExecStartOptions struct {
// ExecStart will first check if it's detached
Detach bool
// Check if there's a tty
Tty bool
// Terminal size [height, width], unused if Tty == false
ConsoleSize *[2]uint `json:",omitempty"`
}
// ExecAttachOptions is a temp struct used by execAttach.
//
// TODO(thaJeztah): make this a separate type; ContainerExecAttach does not use the Detach option, and cannot run detached.
type ExecAttachOptions = ExecStartOptions
// ExecInspect holds information returned by exec inspect.
type ExecInspect struct {
ExecID string `json:"ID"`
ContainerID string
Running bool
ExitCode int
Pid int
}

View File

@@ -1,85 +0,0 @@
package container
import (
"github.com/docker/docker/api/types/network"
"github.com/docker/go-connections/nat"
)
// NetworkSettings exposes the network settings in the api
type NetworkSettings struct {
NetworkSettingsBase
DefaultNetworkSettings
Networks map[string]*network.EndpointSettings
}
// NetworkSettingsBase holds networking state for a container when inspecting it.
//
// Deprecated: Most fields in NetworkSettingsBase are deprecated. Fields which aren't deprecated will move to
// NetworkSettings in v29.0, and this struct will be removed.
type NetworkSettingsBase struct {
Bridge string // Deprecated: This field is only set when the daemon is started with the --bridge flag specified.
SandboxID string // SandboxID uniquely represents a container's network stack
SandboxKey string // SandboxKey identifies the sandbox
Ports nat.PortMap // Ports is a collection of PortBinding indexed by Port
// HairpinMode specifies if hairpin NAT should be enabled on the virtual interface
//
// Deprecated: This field is never set and will be removed in a future release.
HairpinMode bool
// LinkLocalIPv6Address is an IPv6 unicast address using the link-local prefix
//
// Deprecated: This field is never set and will be removed in a future release.
LinkLocalIPv6Address string
// LinkLocalIPv6PrefixLen is the prefix length of an IPv6 unicast address
//
// Deprecated: This field is never set and will be removed in a future release.
LinkLocalIPv6PrefixLen int
SecondaryIPAddresses []network.Address // Deprecated: This field is never set and will be removed in a future release.
SecondaryIPv6Addresses []network.Address // Deprecated: This field is never set and will be removed in a future release.
}
// DefaultNetworkSettings holds the networking state for the default bridge, if the container is connected to that
// network.
//
// Deprecated: this struct is deprecated since Docker v1.11 and will be removed in v29. You should look for the default
// network in NetworkSettings.Networks instead.
type DefaultNetworkSettings struct {
// EndpointID uniquely represents a service endpoint in a Sandbox
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
EndpointID string
// Gateway holds the gateway address for the network
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
Gateway string
// GlobalIPv6Address holds network's global IPv6 address
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
GlobalIPv6Address string
// GlobalIPv6PrefixLen represents mask length of network's global IPv6 address
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
GlobalIPv6PrefixLen int
// IPAddress holds the IPv4 address for the network
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
IPAddress string
// IPPrefixLen represents mask length of network's IPv4 address
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
IPPrefixLen int
// IPv6Gateway holds gateway address specific for IPv6
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
IPv6Gateway string
// MacAddress holds the MAC address for the network
//
// Deprecated: This field will be removed in v29. You should look for the default network in NetworkSettings.Networks instead.
MacAddress string
}
// NetworkSettingsSummary provides a summary of container's networks
// in /containers/json
type NetworkSettingsSummary struct {
Networks map[string]*network.EndpointSettings
}

View File

@@ -1,67 +0,0 @@
package container
import "github.com/docker/docker/api/types/filters"
// ResizeOptions holds parameters to resize a TTY.
// It can be used to resize container TTYs and
// exec process TTYs too.
type ResizeOptions struct {
Height uint
Width uint
}
// AttachOptions holds parameters to attach to a container.
type AttachOptions struct {
Stream bool
Stdin bool
Stdout bool
Stderr bool
DetachKeys string
Logs bool
}
// CommitOptions holds parameters to commit changes into a container.
type CommitOptions struct {
Reference string
Comment string
Author string
Changes []string
Pause bool
Config *Config
}
// RemoveOptions holds parameters to remove containers.
type RemoveOptions struct {
RemoveVolumes bool
RemoveLinks bool
Force bool
}
// StartOptions holds parameters to start containers.
type StartOptions struct {
CheckpointID string
CheckpointDir string
}
// ListOptions holds parameters to list containers with.
type ListOptions struct {
Size bool
All bool
Latest bool
Since string
Before string
Limit int
Filters filters.Args
}
// LogsOptions holds parameters to filter logs with.
type LogsOptions struct {
ShowStdout bool
ShowStderr bool
Since string
Until string
Timestamps bool
Follow bool
Tail string
Details bool
}

View File

@@ -1,24 +0,0 @@
package filters
import "fmt"
// invalidFilter indicates that the provided filter or its value is invalid
type invalidFilter struct {
Filter string
Value []string
}
func (e invalidFilter) Error() string {
msg := "invalid filter"
if e.Filter != "" {
msg += " '" + e.Filter
if e.Value != nil {
msg = fmt.Sprintf("%s=%s", msg, e.Value)
}
msg += "'"
}
return msg
}
// InvalidParameter marks this error as ErrInvalidParameter
func (e invalidFilter) InvalidParameter() {}

View File

@@ -1,61 +0,0 @@
package filters
import (
"encoding/json"
"github.com/docker/docker/api/types/versions"
)
// ToParamWithVersion encodes Args as a JSON string. If version is less than 1.22
// then the encoded format will use an older legacy format where the values are a
// list of strings, instead of a set.
//
// Deprecated: do not use in any new code; use ToJSON instead
func ToParamWithVersion(version string, a Args) (string, error) {
out, err := ToJSON(a)
if out == "" || err != nil {
return "", nil
}
if version != "" && versions.LessThan(version, "1.22") {
return encodeLegacyFilters(out)
}
return out, nil
}
// encodeLegacyFilters encodes Args in the legacy format as used in API v1.21 and older.
// where values are a list of strings, instead of a set.
//
// Don't use in any new code; use [filters.ToJSON]] instead.
func encodeLegacyFilters(currentFormat string) (string, error) {
// The Args.fields field is not exported, but used to marshal JSON,
// so we'll marshal to the new format, then unmarshal to get the
// fields, and marshal again.
//
// This is far from optimal, but this code is only used for deprecated
// API versions, so should not be hit commonly.
var argsFields map[string]map[string]bool
err := json.Unmarshal([]byte(currentFormat), &argsFields)
if err != nil {
return "", err
}
buf, err := json.Marshal(convertArgsToSlice(argsFields))
if err != nil {
return "", err
}
return string(buf), nil
}
func convertArgsToSlice(f map[string]map[string]bool) map[string][]string {
m := map[string][]string{}
for k, v := range f {
values := []string{}
for kk := range v {
if v[kk] {
values = append(values, kk)
}
}
m[k] = values
}
return m
}

View File

@@ -1,302 +0,0 @@
/*
Package filters provides tools for encoding a mapping of keys to a set of
multiple values.
*/
package filters
import (
"encoding/json"
"regexp"
"strings"
)
// Args stores a mapping of keys to a set of multiple values.
type Args struct {
fields map[string]map[string]bool
}
// KeyValuePair are used to initialize a new Args
type KeyValuePair struct {
Key string
Value string
}
// Arg creates a new KeyValuePair for initializing Args
func Arg(key, value string) KeyValuePair {
return KeyValuePair{Key: key, Value: value}
}
// NewArgs returns a new Args populated with the initial args
func NewArgs(initialArgs ...KeyValuePair) Args {
args := Args{fields: map[string]map[string]bool{}}
for _, arg := range initialArgs {
args.Add(arg.Key, arg.Value)
}
return args
}
// Keys returns all the keys in list of Args
func (args Args) Keys() []string {
keys := make([]string, 0, len(args.fields))
for k := range args.fields {
keys = append(keys, k)
}
return keys
}
// MarshalJSON returns a JSON byte representation of the Args
func (args Args) MarshalJSON() ([]byte, error) {
if len(args.fields) == 0 {
return []byte("{}"), nil
}
return json.Marshal(args.fields)
}
// ToJSON returns the Args as a JSON encoded string
func ToJSON(a Args) (string, error) {
if a.Len() == 0 {
return "", nil
}
buf, err := json.Marshal(a)
return string(buf), err
}
// FromJSON decodes a JSON encoded string into Args
func FromJSON(p string) (Args, error) {
args := NewArgs()
if p == "" {
return args, nil
}
raw := []byte(p)
err := json.Unmarshal(raw, &args)
if err == nil {
return args, nil
}
// Fallback to parsing arguments in the legacy slice format
deprecated := map[string][]string{}
if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil {
return args, &invalidFilter{}
}
args.fields = deprecatedArgs(deprecated)
return args, nil
}
// UnmarshalJSON populates the Args from JSON encode bytes
func (args Args) UnmarshalJSON(raw []byte) error {
return json.Unmarshal(raw, &args.fields)
}
// Get returns the list of values associated with the key
func (args Args) Get(key string) []string {
values := args.fields[key]
if values == nil {
return make([]string, 0)
}
slice := make([]string, 0, len(values))
for key := range values {
slice = append(slice, key)
}
return slice
}
// Add a new value to the set of values
func (args Args) Add(key, value string) {
if _, ok := args.fields[key]; ok {
args.fields[key][value] = true
} else {
args.fields[key] = map[string]bool{value: true}
}
}
// Del removes a value from the set
func (args Args) Del(key, value string) {
if _, ok := args.fields[key]; ok {
delete(args.fields[key], value)
if len(args.fields[key]) == 0 {
delete(args.fields, key)
}
}
}
// Len returns the number of keys in the mapping
func (args Args) Len() int {
return len(args.fields)
}
// MatchKVList returns true if all the pairs in sources exist as key=value
// pairs in the mapping at key, or if there are no values at key.
func (args Args) MatchKVList(key string, sources map[string]string) bool {
fieldValues := args.fields[key]
// do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 {
return true
}
if len(sources) == 0 {
return false
}
for value := range fieldValues {
testK, testV, hasValue := strings.Cut(value, "=")
v, ok := sources[testK]
if !ok {
return false
}
if hasValue && testV != v {
return false
}
}
return true
}
// Match returns true if any of the values at key match the source string
func (args Args) Match(field, source string) bool {
if args.ExactMatch(field, source) {
return true
}
fieldValues := args.fields[field]
for name2match := range fieldValues {
match, err := regexp.MatchString(name2match, source)
if err != nil {
continue
}
if match {
return true
}
}
return false
}
// GetBoolOrDefault returns a boolean value of the key if the key is present
// and is interpretable as a boolean value. Otherwise the default value is returned.
// Error is not nil only if the filter values are not valid boolean or are conflicting.
func (args Args) GetBoolOrDefault(key string, defaultValue bool) (bool, error) {
fieldValues, ok := args.fields[key]
if !ok {
return defaultValue, nil
}
if len(fieldValues) == 0 {
return defaultValue, &invalidFilter{key, nil}
}
isFalse := fieldValues["0"] || fieldValues["false"]
isTrue := fieldValues["1"] || fieldValues["true"]
if isFalse == isTrue {
// Either no or conflicting truthy/falsy value were provided
return defaultValue, &invalidFilter{key, args.Get(key)}
}
return isTrue, nil
}
// ExactMatch returns true if the source matches exactly one of the values.
func (args Args) ExactMatch(key, source string) bool {
fieldValues, ok := args.fields[key]
// do not filter if there is no filter set or cannot determine filter
if !ok || len(fieldValues) == 0 {
return true
}
// try to match full name value to avoid O(N) regular expression matching
return fieldValues[source]
}
// UniqueExactMatch returns true if there is only one value and the source
// matches exactly the value.
func (args Args) UniqueExactMatch(key, source string) bool {
fieldValues := args.fields[key]
// do not filter if there is no filter set or cannot determine filter
if len(fieldValues) == 0 {
return true
}
if len(args.fields[key]) != 1 {
return false
}
// try to match full name value to avoid O(N) regular expression matching
return fieldValues[source]
}
// FuzzyMatch returns true if the source matches exactly one value, or the
// source has one of the values as a prefix.
func (args Args) FuzzyMatch(key, source string) bool {
if args.ExactMatch(key, source) {
return true
}
fieldValues := args.fields[key]
for prefix := range fieldValues {
if strings.HasPrefix(source, prefix) {
return true
}
}
return false
}
// Contains returns true if the key exists in the mapping
func (args Args) Contains(field string) bool {
_, ok := args.fields[field]
return ok
}
// Validate compared the set of accepted keys against the keys in the mapping.
// An error is returned if any mapping keys are not in the accepted set.
func (args Args) Validate(accepted map[string]bool) error {
for name := range args.fields {
if !accepted[name] {
return &invalidFilter{name, nil}
}
}
return nil
}
// WalkValues iterates over the list of values for a key in the mapping and calls
// op() for each value. If op returns an error the iteration stops and the
// error is returned.
func (args Args) WalkValues(field string, op func(value string) error) error {
if _, ok := args.fields[field]; !ok {
return nil
}
for v := range args.fields[field] {
if err := op(v); err != nil {
return err
}
}
return nil
}
// Clone returns a copy of args.
func (args Args) Clone() (newArgs Args) {
newArgs.fields = make(map[string]map[string]bool, len(args.fields))
for k, m := range args.fields {
var mm map[string]bool
if m != nil {
mm = make(map[string]bool, len(m))
for kk, v := range m {
mm[kk] = v
}
}
newArgs.fields[k] = mm
}
return newArgs
}
func deprecatedArgs(d map[string][]string) map[string]map[string]bool {
m := map[string]map[string]bool{}
for k, v := range d {
values := map[string]bool{}
for _, vv := range v {
values[vv] = true
}
m[k] = values
}
return m
}

View File

@@ -1,10 +0,0 @@
package image
// DiskUsage contains disk usage for images.
//
// Deprecated: this type is no longer used and will be removed in the next release.
type DiskUsage struct {
TotalSize int64
Reclaimable int64
Items []*Summary
}

View File

@@ -1,47 +0,0 @@
package image
import (
"io"
"time"
)
// Metadata contains engine-local data about the image.
type Metadata struct {
// LastTagTime is the date and time at which the image was last tagged.
LastTagTime time.Time `json:",omitempty"`
}
// PruneReport contains the response for Engine API:
// POST "/images/prune"
type PruneReport struct {
ImagesDeleted []DeleteResponse
SpaceReclaimed uint64
}
// LoadResponse returns information to the client about a load process.
//
// TODO(thaJeztah): remove this type, and just use an io.ReadCloser
//
// This type was added in https://github.com/moby/moby/pull/18878, related
// to https://github.com/moby/moby/issues/19177;
//
// Make docker load to output json when the response content type is json
// Swarm hijacks the response from docker load and returns JSON rather
// than plain text like the Engine does. This makes the API library to return
// information to figure that out.
//
// However the "load" endpoint unconditionally returns JSON;
// https://github.com/moby/moby/blob/7b9d2ef6e5518a3d3f3cc418459f8df786cfbbd1/api/server/router/image/image_routes.go#L248-L255
//
// PR https://github.com/moby/moby/pull/21959 made the response-type depend
// on whether "quiet" was set, but this logic got changed in a follow-up
// https://github.com/moby/moby/pull/25557, which made the JSON response-type
// unconditionally, but the output produced depend on whether"quiet" was set.
//
// We should deprecated the "quiet" option, as it's really a client
// responsibility.
type LoadResponse struct {
// Body must be closed to avoid a resource leak
Body io.ReadCloser
JSON bool
}

View File

@@ -1,124 +0,0 @@
package image
import (
"context"
"io"
"github.com/docker/docker/api/types/filters"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ImportSource holds source information for ImageImport
type ImportSource struct {
Source io.Reader // Source is the data to send to the server to create this image from. You must set SourceName to "-" to leverage this.
SourceName string // SourceName is the name of the image to pull. Set to "-" to leverage the Source attribute.
}
// ImportOptions holds information to import images from the client host.
type ImportOptions struct {
Tag string // Tag is the name to tag this image with. This attribute is deprecated.
Message string // Message is the message to tag the image with
Changes []string // Changes are the raw changes to apply to this image
Platform string // Platform is the target platform of the image
}
// CreateOptions holds information to create images.
type CreateOptions struct {
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry.
Platform string // Platform is the target platform of the image if it needs to be pulled from the registry.
}
// PullOptions holds information to pull images.
type PullOptions struct {
All bool
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
// PrivilegeFunc is a function that clients can supply to retry operations
// after getting an authorization error. This function returns the registry
// authentication header value in base64 encoded format, or an error if the
// privilege request fails.
//
// For details, refer to [github.com/docker/docker/api/types/registry.RequestAuthConfig].
PrivilegeFunc func(context.Context) (string, error)
Platform string
}
// PushOptions holds information to push images.
type PushOptions struct {
All bool
RegistryAuth string // RegistryAuth is the base64 encoded credentials for the registry
// PrivilegeFunc is a function that clients can supply to retry operations
// after getting an authorization error. This function returns the registry
// authentication header value in base64 encoded format, or an error if the
// privilege request fails.
//
// For details, refer to [github.com/docker/docker/api/types/registry.RequestAuthConfig].
PrivilegeFunc func(context.Context) (string, error)
// Platform is an optional field that selects a specific platform to push
// when the image is a multi-platform image.
// Using this will only push a single platform-specific manifest.
Platform *ocispec.Platform `json:",omitempty"`
}
// ListOptions holds parameters to list images with.
type ListOptions struct {
// All controls whether all images in the graph are filtered, or just
// the heads.
All bool
// Filters is a JSON-encoded set of filter arguments.
Filters filters.Args
// SharedSize indicates whether the shared size of images should be computed.
SharedSize bool
// ContainerCount indicates whether container count should be computed.
//
// Deprecated: This field has been unused and is no longer required and will be removed in a future version.
ContainerCount bool
// Manifests indicates whether the image manifests should be returned.
Manifests bool
}
// RemoveOptions holds parameters to remove images.
type RemoveOptions struct {
Platforms []ocispec.Platform
Force bool
PruneChildren bool
}
// HistoryOptions holds parameters to get image history.
type HistoryOptions struct {
// Platform from the manifest list to use for history.
Platform *ocispec.Platform
}
// LoadOptions holds parameters to load images.
type LoadOptions struct {
// Quiet suppresses progress output
Quiet bool
// Platforms selects the platforms to load if the image is a
// multi-platform image and has multiple variants.
Platforms []ocispec.Platform
}
type InspectOptions struct {
// Manifests returns the image manifests.
Manifests bool
// Platform selects the specific platform of a multi-platform image to inspect.
//
// This option is only available for API version 1.49 and up.
Platform *ocispec.Platform
}
// SaveOptions holds parameters to save images.
type SaveOptions struct {
// Platforms selects the platforms to save if the image is a
// multi-platform image and has multiple variants.
Platforms []ocispec.Platform
}

View File

@@ -1,151 +0,0 @@
package network
import (
"errors"
"fmt"
"net"
)
// EndpointSettings stores the network endpoint details
type EndpointSettings struct {
// Configurations
IPAMConfig *EndpointIPAMConfig
Links []string
Aliases []string // Aliases holds the list of extra, user-specified DNS names for this endpoint.
// MacAddress may be used to specify a MAC address when the container is created.
// Once the container is running, it becomes operational data (it may contain a
// generated address).
MacAddress string
DriverOpts map[string]string
// GwPriority determines which endpoint will provide the default gateway
// for the container. The endpoint with the highest priority will be used.
// If multiple endpoints have the same priority, they are lexicographically
// sorted based on their network name, and the one that sorts first is picked.
GwPriority int
// Operational data
NetworkID string
EndpointID string
Gateway string
IPAddress string
IPPrefixLen int
IPv6Gateway string
GlobalIPv6Address string
GlobalIPv6PrefixLen int
// DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to
// generate PTR records.
DNSNames []string
}
// Copy makes a deep copy of `EndpointSettings`
func (es *EndpointSettings) Copy() *EndpointSettings {
epCopy := *es
if es.IPAMConfig != nil {
epCopy.IPAMConfig = es.IPAMConfig.Copy()
}
if es.Links != nil {
links := make([]string, 0, len(es.Links))
epCopy.Links = append(links, es.Links...)
}
if es.Aliases != nil {
aliases := make([]string, 0, len(es.Aliases))
epCopy.Aliases = append(aliases, es.Aliases...)
}
if len(es.DNSNames) > 0 {
epCopy.DNSNames = make([]string, len(es.DNSNames))
copy(epCopy.DNSNames, es.DNSNames)
}
return &epCopy
}
// EndpointIPAMConfig represents IPAM configurations for the endpoint
type EndpointIPAMConfig struct {
IPv4Address string `json:",omitempty"`
IPv6Address string `json:",omitempty"`
LinkLocalIPs []string `json:",omitempty"`
}
// Copy makes a copy of the endpoint ipam config
func (cfg *EndpointIPAMConfig) Copy() *EndpointIPAMConfig {
cfgCopy := *cfg
cfgCopy.LinkLocalIPs = make([]string, 0, len(cfg.LinkLocalIPs))
cfgCopy.LinkLocalIPs = append(cfgCopy.LinkLocalIPs, cfg.LinkLocalIPs...)
return &cfgCopy
}
// NetworkSubnet describes a user-defined subnet for a specific network. It's only used to validate if an
// EndpointIPAMConfig is valid for a specific network.
type NetworkSubnet interface {
// Contains checks whether the NetworkSubnet contains [addr].
Contains(addr net.IP) bool
// IsStatic checks whether the subnet was statically allocated (ie. user-defined).
IsStatic() bool
}
// IsInRange checks whether static IP addresses are valid in a specific network.
func (cfg *EndpointIPAMConfig) IsInRange(v4Subnets []NetworkSubnet, v6Subnets []NetworkSubnet) error {
var errs []error
if err := validateEndpointIPAddress(cfg.IPv4Address, v4Subnets); err != nil {
errs = append(errs, err)
}
if err := validateEndpointIPAddress(cfg.IPv6Address, v6Subnets); err != nil {
errs = append(errs, err)
}
return errJoin(errs...)
}
func validateEndpointIPAddress(epAddr string, ipamSubnets []NetworkSubnet) error {
if epAddr == "" {
return nil
}
var staticSubnet bool
parsedAddr := net.ParseIP(epAddr)
for _, subnet := range ipamSubnets {
if subnet.IsStatic() {
staticSubnet = true
if subnet.Contains(parsedAddr) {
return nil
}
}
}
if staticSubnet {
return fmt.Errorf("no configured subnet or ip-range contain the IP address %s", epAddr)
}
return errors.New("user specified IP address is supported only when connecting to networks with user configured subnets")
}
// Validate checks whether cfg is valid.
func (cfg *EndpointIPAMConfig) Validate() error {
if cfg == nil {
return nil
}
var errs []error
if cfg.IPv4Address != "" {
if addr := net.ParseIP(cfg.IPv4Address); addr == nil || addr.To4() == nil || addr.IsUnspecified() {
errs = append(errs, fmt.Errorf("invalid IPv4 address: %s", cfg.IPv4Address))
}
}
if cfg.IPv6Address != "" {
if addr := net.ParseIP(cfg.IPv6Address); addr == nil || addr.To4() != nil || addr.IsUnspecified() {
errs = append(errs, fmt.Errorf("invalid IPv6 address: %s", cfg.IPv6Address))
}
}
for _, addr := range cfg.LinkLocalIPs {
if parsed := net.ParseIP(addr); parsed == nil || parsed.IsUnspecified() {
errs = append(errs, fmt.Errorf("invalid link-local IP address: %s", addr))
}
}
return errJoin(errs...)
}

View File

@@ -1,173 +0,0 @@
package network
import (
"errors"
"fmt"
"net/netip"
"strings"
)
// IPAM represents IP Address Management
type IPAM struct {
Driver string
Options map[string]string // Per network IPAM driver options
Config []IPAMConfig
}
// IPAMConfig represents IPAM configurations
type IPAMConfig struct {
Subnet string `json:",omitempty"`
IPRange string `json:",omitempty"`
Gateway string `json:",omitempty"`
AuxAddress map[string]string `json:"AuxiliaryAddresses,omitempty"`
}
type ipFamily string
const (
ip4 ipFamily = "IPv4"
ip6 ipFamily = "IPv6"
)
// ValidateIPAM checks whether the network's IPAM passed as argument is valid. It returns a joinError of the list of
// errors found.
func ValidateIPAM(ipam *IPAM, enableIPv6 bool) error {
if ipam == nil {
return nil
}
var errs []error
for _, cfg := range ipam.Config {
subnet, err := netip.ParsePrefix(cfg.Subnet)
if err != nil {
errs = append(errs, fmt.Errorf("invalid subnet %s: invalid CIDR block notation", cfg.Subnet))
continue
}
subnetFamily := ip4
if subnet.Addr().Is6() {
subnetFamily = ip6
}
if !enableIPv6 && subnetFamily == ip6 {
continue
}
if subnet != subnet.Masked() {
errs = append(errs, fmt.Errorf("invalid subnet %s: it should be %s", subnet, subnet.Masked()))
}
if ipRangeErrs := validateIPRange(cfg.IPRange, subnet, subnetFamily); len(ipRangeErrs) > 0 {
errs = append(errs, ipRangeErrs...)
}
if err := validateAddress(cfg.Gateway, subnet, subnetFamily); err != nil {
errs = append(errs, fmt.Errorf("invalid gateway %s: %w", cfg.Gateway, err))
}
for auxName, aux := range cfg.AuxAddress {
if err := validateAddress(aux, subnet, subnetFamily); err != nil {
errs = append(errs, fmt.Errorf("invalid auxiliary address %s: %w", auxName, err))
}
}
}
if err := errJoin(errs...); err != nil {
return fmt.Errorf("invalid network config:\n%w", err)
}
return nil
}
func validateIPRange(ipRange string, subnet netip.Prefix, subnetFamily ipFamily) []error {
if ipRange == "" {
return nil
}
prefix, err := netip.ParsePrefix(ipRange)
if err != nil {
return []error{fmt.Errorf("invalid ip-range %s: invalid CIDR block notation", ipRange)}
}
family := ip4
if prefix.Addr().Is6() {
family = ip6
}
if family != subnetFamily {
return []error{fmt.Errorf("invalid ip-range %s: parent subnet is an %s block", ipRange, subnetFamily)}
}
var errs []error
if prefix.Bits() < subnet.Bits() {
errs = append(errs, fmt.Errorf("invalid ip-range %s: CIDR block is bigger than its parent subnet %s", ipRange, subnet))
}
if prefix != prefix.Masked() {
errs = append(errs, fmt.Errorf("invalid ip-range %s: it should be %s", prefix, prefix.Masked()))
}
if !subnet.Overlaps(prefix) {
errs = append(errs, fmt.Errorf("invalid ip-range %s: parent subnet %s doesn't contain ip-range", ipRange, subnet))
}
return errs
}
func validateAddress(address string, subnet netip.Prefix, subnetFamily ipFamily) error {
if address == "" {
return nil
}
addr, err := netip.ParseAddr(address)
if err != nil {
return errors.New("invalid address")
}
family := ip4
if addr.Is6() {
family = ip6
}
if family != subnetFamily {
return fmt.Errorf("parent subnet is an %s block", subnetFamily)
}
if !subnet.Contains(addr) {
return fmt.Errorf("parent subnet %s doesn't contain this address", subnet)
}
return nil
}
func errJoin(errs ...error) error {
n := 0
for _, err := range errs {
if err != nil {
n++
}
}
if n == 0 {
return nil
}
e := &joinError{
errs: make([]error, 0, n),
}
for _, err := range errs {
if err != nil {
e.errs = append(e.errs, err)
}
}
return e
}
type joinError struct {
errs []error
}
func (e *joinError) Error() string {
if len(e.errs) == 1 {
return strings.TrimSpace(e.errs[0].Error())
}
stringErrs := make([]string, 0, len(e.errs))
for _, subErr := range e.errs {
stringErrs = append(stringErrs, strings.ReplaceAll(subErr.Error(), "\n", "\n\t"))
}
return "* " + strings.Join(stringErrs, "\n* ")
}
func (e *joinError) Unwrap() []error {
return e.errs
}

View File

@@ -1,168 +0,0 @@
package network
import (
"time"
"github.com/docker/docker/api/types/filters"
)
const (
// NetworkDefault is a platform-independent alias to choose the platform-specific default network stack.
NetworkDefault = "default"
// NetworkHost is the name of the predefined network used when the NetworkMode host is selected (only available on Linux)
NetworkHost = "host"
// NetworkNone is the name of the predefined network used when the NetworkMode none is selected (available on both Linux and Windows)
NetworkNone = "none"
// NetworkBridge is the name of the default network on Linux
NetworkBridge = "bridge"
// NetworkNat is the name of the default network on Windows
NetworkNat = "nat"
)
// CreateRequest is the request message sent to the server for network create call.
type CreateRequest struct {
CreateOptions
Name string // Name is the requested name of the network.
// Deprecated: CheckDuplicate is deprecated since API v1.44, but it defaults to true when sent by the client
// package to older daemons.
CheckDuplicate *bool `json:",omitempty"`
}
// CreateOptions holds options to create a network.
type CreateOptions struct {
Driver string // Driver is the driver-name used to create the network (e.g. `bridge`, `overlay`)
Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level).
EnableIPv4 *bool `json:",omitempty"` // EnableIPv4 represents whether to enable IPv4.
EnableIPv6 *bool `json:",omitempty"` // EnableIPv6 represents whether to enable IPv6.
IPAM *IPAM // IPAM is the network's IP Address Management.
Internal bool // Internal represents if the network is used internal only.
Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster.
ConfigOnly bool // ConfigOnly creates a config-only network. Config-only networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services.
ConfigFrom *ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network. The specified network must be a config-only network; see [CreateOptions.ConfigOnly].
Options map[string]string // Options specifies the network-specific options to use for when creating the network.
Labels map[string]string // Labels holds metadata specific to the network being created.
}
// ListOptions holds parameters to filter the list of networks with.
type ListOptions struct {
Filters filters.Args
}
// InspectOptions holds parameters to inspect network.
type InspectOptions struct {
Scope string
Verbose bool
}
// ConnectOptions represents the data to be used to connect a container to the
// network.
type ConnectOptions struct {
Container string
EndpointConfig *EndpointSettings `json:",omitempty"`
}
// DisconnectOptions represents the data to be used to disconnect a container
// from the network.
type DisconnectOptions struct {
Container string
Force bool
}
// Inspect is the body of the "get network" http response message.
type Inspect struct {
Name string // Name is the name of the network
ID string `json:"Id"` // ID uniquely identifies a network on a single machine
Created time.Time // Created is the time the network created
Scope string // Scope describes the level at which the network exists (e.g. `swarm` for cluster-wide or `local` for machine level)
Driver string // Driver is the Driver name used to create the network (e.g. `bridge`, `overlay`)
EnableIPv4 bool // EnableIPv4 represents whether IPv4 is enabled
EnableIPv6 bool // EnableIPv6 represents whether IPv6 is enabled
IPAM IPAM // IPAM is the network's IP Address Management
Internal bool // Internal represents if the network is used internal only
Attachable bool // Attachable represents if the global scope is manually attachable by regular containers from workers in swarm mode.
Ingress bool // Ingress indicates the network is providing the routing-mesh for the swarm cluster.
ConfigFrom ConfigReference // ConfigFrom specifies the source which will provide the configuration for this network.
ConfigOnly bool // ConfigOnly networks are place-holder networks for network configurations to be used by other networks. ConfigOnly networks cannot be used directly to run containers or services.
Containers map[string]EndpointResource // Containers contains endpoints belonging to the network
Options map[string]string // Options holds the network specific options to use for when creating the network
Labels map[string]string // Labels holds metadata specific to the network being created
Peers []PeerInfo `json:",omitempty"` // List of peer nodes for an overlay network
Services map[string]ServiceInfo `json:",omitempty"`
}
// Summary is used as response when listing networks. It currently is an alias
// for [Inspect], but may diverge in the future, as not all information may
// be included when listing networks.
type Summary = Inspect
// Address represents an IP address
type Address struct {
Addr string
PrefixLen int
}
// PeerInfo represents one peer of an overlay network
type PeerInfo struct {
Name string
IP string
}
// Task carries the information about one backend task
type Task struct {
Name string
EndpointID string
EndpointIP string
Info map[string]string
}
// ServiceInfo represents service parameters with the list of service's tasks
type ServiceInfo struct {
VIP string
Ports []string
LocalLBIndex int
Tasks []Task
}
// EndpointResource contains network resources allocated and used for a
// container in a network.
type EndpointResource struct {
Name string
EndpointID string
MacAddress string
IPv4Address string
IPv6Address string
}
// NetworkingConfig represents the container's networking configuration for each of its interfaces
// Carries the networking configs specified in the `docker run` and `docker network connect` commands
type NetworkingConfig struct {
EndpointsConfig map[string]*EndpointSettings // Endpoint configs for each connecting network
}
// ConfigReference specifies the source which provides a network's configuration
type ConfigReference struct {
Network string
}
var acceptedFilters = map[string]bool{
"dangling": true,
"driver": true,
"id": true,
"label": true,
"name": true,
"scope": true,
"type": true,
}
// ValidateFilters validates the list of filter args with the available filters.
func ValidateFilters(filter filters.Args) error {
return filter.Validate(acceptedFilters)
}
// PruneReport contains the response for Engine API:
// POST "/networks/prune"
type PruneReport struct {
NetworksDeleted []string
}

View File

@@ -1,21 +0,0 @@
package types
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// PluginInterfaceType plugin interface type
// swagger:model PluginInterfaceType
type PluginInterfaceType struct {
// capability
// Required: true
Capability string `json:"Capability"`
// prefix
// Required: true
Prefix string `json:"Prefix"`
// version
// Required: true
Version string `json:"Version"`
}

View File

@@ -1,71 +0,0 @@
package types
import (
"encoding/json"
"fmt"
"sort"
)
// PluginsListResponse contains the response for the Engine API
type PluginsListResponse []*Plugin
// UnmarshalJSON implements json.Unmarshaler for PluginInterfaceType
func (t *PluginInterfaceType) UnmarshalJSON(p []byte) error {
versionIndex := len(p)
prefixIndex := 0
if len(p) < 2 || p[0] != '"' || p[len(p)-1] != '"' {
return fmt.Errorf("%q is not a plugin interface type", p)
}
p = p[1 : len(p)-1]
loop:
for i, b := range p {
switch b {
case '.':
prefixIndex = i
case '/':
versionIndex = i
break loop
}
}
t.Prefix = string(p[:prefixIndex])
t.Capability = string(p[prefixIndex+1 : versionIndex])
if versionIndex < len(p) {
t.Version = string(p[versionIndex+1:])
}
return nil
}
// MarshalJSON implements json.Marshaler for PluginInterfaceType
func (t *PluginInterfaceType) MarshalJSON() ([]byte, error) {
return json.Marshal(t.String())
}
// String implements fmt.Stringer for PluginInterfaceType
func (t PluginInterfaceType) String() string {
return fmt.Sprintf("%s.%s/%s", t.Prefix, t.Capability, t.Version)
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
type PluginPrivilege struct {
Name string
Description string
Value []string
}
// PluginPrivileges is a list of PluginPrivilege
type PluginPrivileges []PluginPrivilege
func (s PluginPrivileges) Len() int {
return len(s)
}
func (s PluginPrivileges) Less(i, j int) bool {
return s[i].Name < s[j].Name
}
func (s PluginPrivileges) Swap(i, j int) {
sort.Strings(s[i].Value)
sort.Strings(s[j].Value)
s[i], s[j] = s[j], s[i]
}

View File

@@ -1,112 +0,0 @@
package registry
import (
"context"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"strings"
)
// AuthHeader is the name of the header used to send encoded registry
// authorization credentials for registry operations (push/pull).
const AuthHeader = "X-Registry-Auth"
// RequestAuthConfig is a function interface that clients can supply
// to retry operations after getting an authorization error.
//
// The function must return the [AuthHeader] value ([AuthConfig]), encoded
// in base64url format ([RFC4648, section 5]), which can be decoded by
// [DecodeAuthConfig].
//
// It must return an error if the privilege request fails.
//
// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
type RequestAuthConfig func(context.Context) (string, error)
// AuthConfig contains authorization information for connecting to a Registry.
type AuthConfig struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Auth string `json:"auth,omitempty"`
// Email is an optional value associated with the username.
//
// Deprecated: This field is deprecated since docker 1.11 (API v1.23) and will be removed in the next release.
Email string `json:"email,omitempty"`
ServerAddress string `json:"serveraddress,omitempty"`
// IdentityToken is used to authenticate the user and get
// an access token for the registry.
IdentityToken string `json:"identitytoken,omitempty"`
// RegistryToken is a bearer token to be sent to a registry
RegistryToken string `json:"registrytoken,omitempty"`
}
// EncodeAuthConfig serializes the auth configuration as a base64url encoded
// ([RFC4648, section 5]) JSON string for sending through the X-Registry-Auth header.
//
// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
func EncodeAuthConfig(authConfig AuthConfig) (string, error) {
buf, err := json.Marshal(authConfig)
if err != nil {
return "", errInvalidParameter{err}
}
return base64.URLEncoding.EncodeToString(buf), nil
}
// DecodeAuthConfig decodes base64url encoded ([RFC4648, section 5]) JSON
// authentication information as sent through the X-Registry-Auth header.
//
// This function always returns an [AuthConfig], even if an error occurs. It is up
// to the caller to decide if authentication is required, and if the error can
// be ignored.
//
// [RFC4648, section 5]: https://tools.ietf.org/html/rfc4648#section-5
func DecodeAuthConfig(authEncoded string) (*AuthConfig, error) {
if authEncoded == "" {
return &AuthConfig{}, nil
}
authJSON := base64.NewDecoder(base64.URLEncoding, strings.NewReader(authEncoded))
return decodeAuthConfigFromReader(authJSON)
}
// DecodeAuthConfigBody decodes authentication information as sent as JSON in the
// body of a request. This function is to provide backward compatibility with old
// clients and API versions. Current clients and API versions expect authentication
// to be provided through the X-Registry-Auth header.
//
// Like [DecodeAuthConfig], this function always returns an [AuthConfig], even if an
// error occurs. It is up to the caller to decide if authentication is required,
// and if the error can be ignored.
//
// Deprecated: this function is no longer used and will be removed in the next release.
func DecodeAuthConfigBody(rdr io.ReadCloser) (*AuthConfig, error) {
return decodeAuthConfigFromReader(rdr)
}
func decodeAuthConfigFromReader(rdr io.Reader) (*AuthConfig, error) {
authConfig := &AuthConfig{}
if err := json.NewDecoder(rdr).Decode(authConfig); err != nil {
// always return an (empty) AuthConfig to increase compatibility with
// the existing API.
return &AuthConfig{}, invalid(err)
}
return authConfig, nil
}
func invalid(err error) error {
return errInvalidParameter{fmt.Errorf("invalid X-Registry-Auth header: %w", err)}
}
type errInvalidParameter struct{ error }
func (errInvalidParameter) InvalidParameter() {}
func (e errInvalidParameter) Cause() error { return e.error }
func (e errInvalidParameter) Unwrap() error { return e.error }

View File

@@ -1,21 +0,0 @@
package registry
// ----------------------------------------------------------------------------
// DO NOT EDIT THIS FILE
// This file was generated by `swagger generate operation`
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
// AuthenticateOKBody authenticate o k body
// swagger:model AuthenticateOKBody
type AuthenticateOKBody struct {
// An opaque token used to authenticate a user after a successful login
// Required: true
IdentityToken string `json:"IdentityToken"`
// The status of the authentication
// Required: true
Status string `json:"Status"`
}

View File

@@ -1,122 +0,0 @@
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
//go:build go1.23
package registry
import (
"encoding/json"
"net"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ServiceConfig stores daemon registry services configuration.
type ServiceConfig struct {
AllowNondistributableArtifactsCIDRs []*NetIPNet `json:"AllowNondistributableArtifactsCIDRs,omitempty"` // Deprecated: non-distributable artifacts are deprecated and enabled by default. This field will be removed in the next release.
AllowNondistributableArtifactsHostnames []string `json:"AllowNondistributableArtifactsHostnames,omitempty"` // Deprecated: non-distributable artifacts are deprecated and enabled by default. This field will be removed in the next release.
InsecureRegistryCIDRs []*NetIPNet `json:"InsecureRegistryCIDRs"`
IndexConfigs map[string]*IndexInfo `json:"IndexConfigs"`
Mirrors []string
// ExtraFields is for internal use to include deprecated fields on older API versions.
ExtraFields map[string]any `json:"-"`
}
// MarshalJSON implements a custom marshaler to include legacy fields
// in API responses.
func (sc *ServiceConfig) MarshalJSON() ([]byte, error) {
type tmp ServiceConfig
base, err := json.Marshal((*tmp)(sc))
if err != nil {
return nil, err
}
var merged map[string]any
_ = json.Unmarshal(base, &merged)
for k, v := range sc.ExtraFields {
merged[k] = v
}
return json.Marshal(merged)
}
// NetIPNet is the net.IPNet type, which can be marshalled and
// unmarshalled to JSON
type NetIPNet net.IPNet
// String returns the CIDR notation of ipnet
func (ipnet *NetIPNet) String() string {
return (*net.IPNet)(ipnet).String()
}
// MarshalJSON returns the JSON representation of the IPNet
func (ipnet *NetIPNet) MarshalJSON() ([]byte, error) {
return json.Marshal((*net.IPNet)(ipnet).String())
}
// UnmarshalJSON sets the IPNet from a byte array of JSON
func (ipnet *NetIPNet) UnmarshalJSON(b []byte) error {
var ipnetStr string
if err := json.Unmarshal(b, &ipnetStr); err != nil {
return err
}
_, cidr, err := net.ParseCIDR(ipnetStr)
if err != nil {
return err
}
*ipnet = NetIPNet(*cidr)
return nil
}
// IndexInfo contains information about a registry
//
// RepositoryInfo Examples:
//
// {
// "Index" : {
// "Name" : "docker.io",
// "Mirrors" : ["https://registry-2.docker.io/v1/", "https://registry-3.docker.io/v1/"],
// "Secure" : true,
// "Official" : true,
// },
// "RemoteName" : "library/debian",
// "LocalName" : "debian",
// "CanonicalName" : "docker.io/debian"
// "Official" : true,
// }
//
// {
// "Index" : {
// "Name" : "127.0.0.1:5000",
// "Mirrors" : [],
// "Secure" : false,
// "Official" : false,
// },
// "RemoteName" : "user/repo",
// "LocalName" : "127.0.0.1:5000/user/repo",
// "CanonicalName" : "127.0.0.1:5000/user/repo",
// "Official" : false,
// }
type IndexInfo struct {
// Name is the name of the registry, such as "docker.io"
Name string
// Mirrors is a list of mirrors, expressed as URIs
Mirrors []string
// Secure is set to false if the registry is part of the list of
// insecure registries. Insecure registries accept HTTP and/or accept
// HTTPS with certificates from unknown CAs.
Secure bool
// Official indicates whether this is an official registry
Official bool
}
// DistributionInspect describes the result obtained from contacting the
// registry to retrieve image metadata
type DistributionInspect struct {
// Descriptor contains information about the manifest, including
// the content addressable digest
Descriptor ocispec.Descriptor
// Platforms contains the list of platforms supported by the image,
// obtained by parsing the manifest
Platforms []ocispec.Platform
}

View File

@@ -1,30 +0,0 @@
package strslice
import "encoding/json"
// StrSlice represents a string or an array of strings.
// We need to override the json decoder to accept both options.
type StrSlice []string
// UnmarshalJSON decodes the byte slice whether it's a string or an array of
// strings. This method is needed to implement json.Unmarshaler.
func (e *StrSlice) UnmarshalJSON(b []byte) error {
if len(b) == 0 {
// With no input, we preserve the existing value by returning nil and
// leaving the target alone. This allows defining default values for
// the type.
return nil
}
p := make([]string, 0, 1)
if err := json.Unmarshal(b, &p); err != nil {
var s string
if err := json.Unmarshal(b, &s); err != nil {
return err
}
p = append(p, s)
}
*e = p
return nil
}

View File

@@ -1,27 +0,0 @@
package runtime
import "fmt"
// PluginSpec defines the base payload which clients can specify for creating
// a service with the plugin runtime.
type PluginSpec struct {
Name string `json:"name,omitempty"`
Remote string `json:"remote,omitempty"`
Privileges []*PluginPrivilege `json:"privileges,omitempty"`
Disabled bool `json:"disabled,omitempty"`
Env []string `json:"env,omitempty"`
}
// PluginPrivilege describes a permission the user has to accept
// upon installing a plugin.
type PluginPrivilege struct {
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Value []string `json:"value,omitempty"`
}
var (
ErrInvalidLengthPlugin = fmt.Errorf("proto: negative length found during unmarshaling") // Deprecated: this error was only used internally and is no longer used.
ErrIntOverflowPlugin = fmt.Errorf("proto: integer overflow") // Deprecated: this error was only used internally and is no longer used.
ErrUnexpectedEndOfGroupPlugin = fmt.Errorf("proto: unexpected end of group") // Deprecated: this error was only used internally and is no longer used.
)

View File

@@ -1,48 +0,0 @@
package system
import (
"errors"
"fmt"
"strings"
)
// SecurityOpt contains the name and options of a security option
type SecurityOpt struct {
Name string
Options []KeyValue
}
// DecodeSecurityOptions decodes a security options string slice to a
// type-safe [SecurityOpt].
func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) {
so := []SecurityOpt{}
for _, opt := range opts {
// support output from a < 1.13 docker daemon
if !strings.Contains(opt, "=") {
so = append(so, SecurityOpt{Name: opt})
continue
}
secopt := SecurityOpt{}
for _, s := range strings.Split(opt, ",") {
k, v, ok := strings.Cut(s, "=")
if !ok {
return nil, fmt.Errorf("invalid security option %q", s)
}
if k == "" || v == "" {
return nil, errors.New("invalid empty security option")
}
if k == "name" {
secopt.Name = v
continue
}
secopt.Options = append(secopt.Options, KeyValue{Key: k, Value: v})
}
so = append(so, secopt)
}
return so, nil
}
// KeyValue holds a key/value pair.
type KeyValue struct {
Key, Value string
}

View File

@@ -1,103 +0,0 @@
package types
import (
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/volume"
)
const (
// MediaTypeRawStream is vendor specific MIME-Type set for raw TTY streams
MediaTypeRawStream = "application/vnd.docker.raw-stream"
// MediaTypeMultiplexedStream is vendor specific MIME-Type set for stdin/stdout/stderr multiplexed streams
MediaTypeMultiplexedStream = "application/vnd.docker.multiplexed-stream"
)
// Ping contains response of Engine API:
// GET "/_ping"
type Ping struct {
APIVersion string
OSType string
Experimental bool
BuilderVersion build.BuilderVersion
// SwarmStatus provides information about the current swarm status of the
// engine, obtained from the "Swarm" header in the API response.
//
// It can be a nil struct if the API version does not provide this header
// in the ping response, or if an error occurred, in which case the client
// should use other ways to get the current swarm status, such as the /swarm
// endpoint.
SwarmStatus *swarm.Status
}
// ComponentVersion describes the version information for a specific component.
type ComponentVersion struct {
Name string
Version string
Details map[string]string `json:",omitempty"`
}
// Version contains response of Engine API:
// GET "/version"
type Version struct {
Platform struct{ Name string } `json:",omitempty"`
Components []ComponentVersion `json:",omitempty"`
// The following fields are deprecated, they relate to the Engine component and are kept for backwards compatibility
Version string
APIVersion string `json:"ApiVersion"`
MinAPIVersion string `json:"MinAPIVersion,omitempty"`
GitCommit string
GoVersion string
Os string
Arch string
KernelVersion string `json:",omitempty"`
Experimental bool `json:",omitempty"`
BuildTime string `json:",omitempty"`
}
// DiskUsageObject represents an object type used for disk usage query filtering.
type DiskUsageObject string
const (
// ContainerObject represents a container DiskUsageObject.
ContainerObject DiskUsageObject = "container"
// ImageObject represents an image DiskUsageObject.
ImageObject DiskUsageObject = "image"
// VolumeObject represents a volume DiskUsageObject.
VolumeObject DiskUsageObject = "volume"
// BuildCacheObject represents a build-cache DiskUsageObject.
BuildCacheObject DiskUsageObject = "build-cache"
)
// DiskUsageOptions holds parameters for system disk usage query.
type DiskUsageOptions struct {
// Types specifies what object types to include in the response. If empty,
// all object types are returned.
Types []DiskUsageObject
}
// DiskUsage contains response of Engine API:
// GET "/system/df"
type DiskUsage struct {
LayersSize int64
Images []*image.Summary
Containers []*container.Summary
Volumes []*volume.Volume
BuildCache []*build.CacheRecord
BuilderSize int64 `json:",omitempty"` // Deprecated: deprecated in API 1.38, and no longer used since API 1.40.
}
// PushResult contains the tag, manifest digest, and manifest size from the
// push. It's used to signal this information to the trust code in the client
// so it can sign the manifest if necessary.
type PushResult struct {
Tag string
Digest string
Size int
}

View File

@@ -1,242 +0,0 @@
package types
import (
"context"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/common"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/storage"
"github.com/docker/docker/api/types/swarm"
)
// IDResponse Response to an API call that returns just an Id.
//
// Deprecated: use either [container.CommitResponse] or [container.ExecCreateResponse]. It will be removed in the next release.
type IDResponse = common.IDResponse
// ContainerJSONBase contains response of Engine API GET "/containers/{name:.*}/json"
// for API version 1.18 and older.
//
// Deprecated: use [container.InspectResponse] or [container.ContainerJSONBase]. It will be removed in the next release.
type ContainerJSONBase = container.ContainerJSONBase
// ContainerJSON is the response for the GET "/containers/{name:.*}/json"
// endpoint.
//
// Deprecated: use [container.InspectResponse]. It will be removed in the next release.
type ContainerJSON = container.InspectResponse
// Container contains response of Engine API:
// GET "/containers/json"
//
// Deprecated: use [container.Summary].
type Container = container.Summary
// ContainerState stores container's running state
//
// Deprecated: use [container.State].
type ContainerState = container.State
// NetworkSettings exposes the network settings in the api.
//
// Deprecated: use [container.NetworkSettings].
type NetworkSettings = container.NetworkSettings
// NetworkSettingsBase holds networking state for a container when inspecting it.
//
// Deprecated: [container.NetworkSettingsBase] will be removed in v29. Prefer
// accessing the fields it contains through [container.NetworkSettings].
type NetworkSettingsBase = container.NetworkSettingsBase //nolint:staticcheck // ignore SA1019: NetworkSettingsBase is deprecated in v28.4.
// DefaultNetworkSettings holds network information
// during the 2 release deprecation period.
// It will be removed in Docker 1.11.
//
// Deprecated: use [container.DefaultNetworkSettings].
type DefaultNetworkSettings = container.DefaultNetworkSettings //nolint:staticcheck // ignore SA1019: DefaultNetworkSettings is deprecated in v28.4.
// SummaryNetworkSettings provides a summary of container's networks
// in /containers/json.
//
// Deprecated: use [container.NetworkSettingsSummary].
type SummaryNetworkSettings = container.NetworkSettingsSummary
// Health states
const (
NoHealthcheck = container.NoHealthcheck // Deprecated: use [container.NoHealthcheck].
Starting = container.Starting // Deprecated: use [container.Starting].
Healthy = container.Healthy // Deprecated: use [container.Healthy].
Unhealthy = container.Unhealthy // Deprecated: use [container.Unhealthy].
)
// Health stores information about the container's healthcheck results.
//
// Deprecated: use [container.Health].
type Health = container.Health
// HealthcheckResult stores information about a single run of a healthcheck probe.
//
// Deprecated: use [container.HealthcheckResult].
type HealthcheckResult = container.HealthcheckResult
// MountPoint represents a mount point configuration inside the container.
// This is used for reporting the mountpoints in use by a container.
//
// Deprecated: use [container.MountPoint].
type MountPoint = container.MountPoint
// Port An open port on a container
//
// Deprecated: use [container.Port].
type Port = container.Port
// GraphDriverData Information about the storage driver used to store the container's and
// image's filesystem.
//
// Deprecated: use [storage.DriverData].
type GraphDriverData = storage.DriverData
// RootFS returns Image's RootFS description including the layer IDs.
//
// Deprecated: use [image.RootFS].
type RootFS = image.RootFS
// ImageInspect contains response of Engine API:
// GET "/images/{name:.*}/json"
//
// Deprecated: use [image.InspectResponse].
type ImageInspect = image.InspectResponse
// RequestPrivilegeFunc is a function interface that clients can supply to
// retry operations after getting an authorization error.
// This function returns the registry authentication header value in base64
// format, or an error if the privilege request fails.
//
// Deprecated: moved to [github.com/docker/docker/api/types/registry.RequestAuthConfig].
type RequestPrivilegeFunc func(context.Context) (string, error)
// SecretCreateResponse contains the information returned to a client
// on the creation of a new secret.
//
// Deprecated: use [swarm.SecretCreateResponse].
type SecretCreateResponse = swarm.SecretCreateResponse
// SecretListOptions holds parameters to list secrets
//
// Deprecated: use [swarm.SecretListOptions].
type SecretListOptions = swarm.SecretListOptions
// ConfigCreateResponse contains the information returned to a client
// on the creation of a new config.
//
// Deprecated: use [swarm.ConfigCreateResponse].
type ConfigCreateResponse = swarm.ConfigCreateResponse
// ConfigListOptions holds parameters to list configs
//
// Deprecated: use [swarm.ConfigListOptions].
type ConfigListOptions = swarm.ConfigListOptions
// NodeListOptions holds parameters to list nodes with.
//
// Deprecated: use [swarm.NodeListOptions].
type NodeListOptions = swarm.NodeListOptions
// NodeRemoveOptions holds parameters to remove nodes with.
//
// Deprecated: use [swarm.NodeRemoveOptions].
type NodeRemoveOptions = swarm.NodeRemoveOptions
// TaskListOptions holds parameters to list tasks with.
//
// Deprecated: use [swarm.TaskListOptions].
type TaskListOptions = swarm.TaskListOptions
// ServiceCreateOptions contains the options to use when creating a service.
//
// Deprecated: use [swarm.ServiceCreateOptions].
type ServiceCreateOptions = swarm.ServiceCreateOptions
// ServiceUpdateOptions contains the options to be used for updating services.
//
// Deprecated: use [swarm.ServiceCreateOptions].
type ServiceUpdateOptions = swarm.ServiceUpdateOptions
const (
RegistryAuthFromSpec = swarm.RegistryAuthFromSpec // Deprecated: use [swarm.RegistryAuthFromSpec].
RegistryAuthFromPreviousSpec = swarm.RegistryAuthFromPreviousSpec // Deprecated: use [swarm.RegistryAuthFromPreviousSpec].
)
// ServiceListOptions holds parameters to list services with.
//
// Deprecated: use [swarm.ServiceListOptions].
type ServiceListOptions = swarm.ServiceListOptions
// ServiceInspectOptions holds parameters related to the "service inspect"
// operation.
//
// Deprecated: use [swarm.ServiceInspectOptions].
type ServiceInspectOptions = swarm.ServiceInspectOptions
// SwarmUnlockKeyResponse contains the response for Engine API:
// GET /swarm/unlockkey
//
// Deprecated: use [swarm.UnlockKeyResponse].
type SwarmUnlockKeyResponse = swarm.UnlockKeyResponse
// BuildCache contains information about a build cache record.
//
// Deprecated: deprecated in API 1.49. Use [build.CacheRecord] instead.
type BuildCache = build.CacheRecord
// BuildCachePruneOptions hold parameters to prune the build cache
//
// Deprecated: use [build.CachePruneOptions].
type BuildCachePruneOptions = build.CachePruneOptions
// BuildCachePruneReport contains the response for Engine API:
// POST "/build/prune"
//
// Deprecated: use [build.CachePruneReport].
type BuildCachePruneReport = build.CachePruneReport
// BuildResult contains the image id of a successful build/
//
// Deprecated: use [build.Result].
type BuildResult = build.Result
// ImageBuildOptions holds the information
// necessary to build images.
//
// Deprecated: use [build.ImageBuildOptions].
type ImageBuildOptions = build.ImageBuildOptions
// ImageBuildOutput defines configuration for exporting a build result
//
// Deprecated: use [build.ImageBuildOutput].
type ImageBuildOutput = build.ImageBuildOutput
// ImageBuildResponse holds information
// returned by a server after building
// an image.
//
// Deprecated: use [build.ImageBuildResponse].
type ImageBuildResponse = build.ImageBuildResponse
// BuilderVersion sets the version of underlying builder to use
//
// Deprecated: use [build.BuilderVersion].
type BuilderVersion = build.BuilderVersion
const (
// BuilderV1 is the first generation builder in docker daemon
//
// Deprecated: use [build.BuilderV1].
BuilderV1 = build.BuilderV1
// BuilderBuildKit is builder based on moby/buildkit project
//
// Deprecated: use [build.BuilderBuildKit].
BuilderBuildKit = build.BuilderBuildKit
)

View File

@@ -1,10 +0,0 @@
package volume
// DiskUsage contains disk usage for volumes.
//
// Deprecated: this type is no longer used and will be removed in the next release.
type DiskUsage struct {
TotalSize int64
Reclaimable int64
Items []*Volume
}

View File

@@ -1,7 +0,0 @@
package volume
// UpdateOptions is configuration to update a Volume with.
type UpdateOptions struct {
// Spec is the ClusterVolumeSpec to update the volume to.
Spec *ClusterVolumeSpec `json:"Spec,omitempty"`
}

View File

@@ -1,38 +0,0 @@
# Go client for the Docker Engine API
The `docker` command uses this package to communicate with the daemon. It can
also be used by your own Go applications to do anything the command-line
interface does running containers, pulling images, managing swarms, etc.
For example, to list all containers (the equivalent of `docker ps --all`):
```go
package main
import (
"context"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
)
func main() {
apiClient, err := client.NewClientWithOpts(client.FromEnv)
if err != nil {
panic(err)
}
defer apiClient.Close()
containers, err := apiClient.ContainerList(context.Background(), container.ListOptions{All: true})
if err != nil {
panic(err)
}
for _, ctr := range containers {
fmt.Printf("%s %s (status: %s)\n", ctr.ID, ctr.Image, ctr.Status)
}
}
```
[Full documentation is available on pkg.go.dev.](https://pkg.go.dev/github.com/docker/docker/client)

View File

@@ -1,16 +0,0 @@
package client
import (
"context"
"net/url"
)
// BuildCancel requests the daemon to cancel the ongoing build request.
func (cli *Client) BuildCancel(ctx context.Context, id string) error {
query := url.Values{}
query.Set("id", id)
resp, err := cli.post(ctx, "/build/cancel", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,56 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"strconv"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/filters"
"github.com/pkg/errors"
)
// BuildCachePrune requests the daemon to delete unused cache data
func (cli *Client) BuildCachePrune(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error) {
if err := cli.NewVersionError(ctx, "1.31", "build prune"); err != nil {
return nil, err
}
query := url.Values{}
if opts.All {
query.Set("all", "1")
}
if opts.KeepStorage != 0 {
query.Set("keep-storage", strconv.Itoa(int(opts.KeepStorage)))
}
if opts.ReservedSpace != 0 {
query.Set("reserved-space", strconv.Itoa(int(opts.ReservedSpace)))
}
if opts.MaxUsedSpace != 0 {
query.Set("max-used-space", strconv.Itoa(int(opts.MaxUsedSpace)))
}
if opts.MinFreeSpace != 0 {
query.Set("min-free-space", strconv.Itoa(int(opts.MinFreeSpace)))
}
f, err := filters.ToJSON(opts.Filters)
if err != nil {
return nil, errors.Wrap(err, "prune could not marshal filters option")
}
query.Set("filters", f)
resp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
report := build.CachePruneReport{}
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return nil, errors.Wrap(err, "error retrieving disk usage")
}
return &report, nil
}

View File

@@ -1,18 +0,0 @@
package client
import (
"context"
"github.com/docker/docker/api/types/checkpoint"
)
// CheckpointAPIClient defines API client methods for the checkpoints.
//
// Experimental: checkpoint and restore is still an experimental feature,
// and only available if the daemon is running with experimental features
// enabled.
type CheckpointAPIClient interface {
CheckpointCreate(ctx context.Context, container string, options checkpoint.CreateOptions) error
CheckpointDelete(ctx context.Context, container string, options checkpoint.DeleteOptions) error
CheckpointList(ctx context.Context, container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error)
}

View File

@@ -1,19 +0,0 @@
package client
import (
"context"
"github.com/docker/docker/api/types/checkpoint"
)
// CheckpointCreate creates a checkpoint from the given container with the given name
func (cli *Client) CheckpointCreate(ctx context.Context, containerID string, options checkpoint.CreateOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/checkpoints", nil, options, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,25 +0,0 @@
package client
import (
"context"
"net/url"
"github.com/docker/docker/api/types/checkpoint"
)
// CheckpointDelete deletes the checkpoint with the given name from the given container
func (cli *Client) CheckpointDelete(ctx context.Context, containerID string, options checkpoint.DeleteOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
query := url.Values{}
if options.CheckpointDir != "" {
query.Set("dir", options.CheckpointDir)
}
resp, err := cli.delete(ctx, "/containers/"+containerID+"/checkpoints/"+options.CheckpointID, query, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,28 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types/checkpoint"
)
// CheckpointList returns the checkpoints of the given container in the docker host
func (cli *Client) CheckpointList(ctx context.Context, container string, options checkpoint.ListOptions) ([]checkpoint.Summary, error) {
var checkpoints []checkpoint.Summary
query := url.Values{}
if options.CheckpointDir != "" {
query.Set("dir", options.CheckpointDir)
}
resp, err := cli.get(ctx, "/containers/"+container+"/checkpoints", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return checkpoints, err
}
err = json.NewDecoder(resp.Body).Decode(&checkpoints)
return checkpoints, err
}

View File

@@ -1,27 +0,0 @@
package client
import "net/http"
// NewClient initializes a new API client for the given host and API version.
// It uses the given http client as transport.
// It also initializes the custom http headers to add to each request.
//
// It won't send any version information if the version number is empty. It is
// highly recommended that you set a version or your client may break if the
// server is upgraded.
//
// Deprecated: use [NewClientWithOpts] passing the [WithHost], [WithVersion],
// [WithHTTPClient] and [WithHTTPHeaders] options. We recommend enabling API
// version negotiation by passing the [WithAPIVersionNegotiation] option instead
// of WithVersion.
func NewClient(host string, version string, client *http.Client, httpHeaders map[string]string) (*Client, error) {
return NewClientWithOpts(WithHost(host), WithVersion(version), WithHTTPClient(client), WithHTTPHeaders(httpHeaders))
}
// NewEnvClient initializes a new API client based on environment variables.
// See FromEnv for a list of support environment variables.
//
// Deprecated: use [NewClientWithOpts] passing the [FromEnv] option.
func NewEnvClient() (*Client, error) {
return NewClientWithOpts(FromEnv)
}

View File

@@ -1,237 +0,0 @@
package client
import (
"context"
"io"
"net"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/system"
"github.com/docker/docker/api/types/volume"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
//
// Deprecated: use [APIClient] instead. This type will be an alias for [APIClient] in the next release, and removed after.
type CommonAPIClient = stableAPIClient
// APIClient is an interface that clients that talk with a docker server must implement.
type APIClient interface {
stableAPIClient
CheckpointAPIClient // CheckpointAPIClient is still experimental.
}
type stableAPIClient interface {
ConfigAPIClient
ContainerAPIClient
DistributionAPIClient
ImageAPIClient
NetworkAPIClient
PluginAPIClient
SystemAPIClient
VolumeAPIClient
ClientVersion() string
DaemonHost() string
HTTPClient() *http.Client
ServerVersion(ctx context.Context) (types.Version, error)
NegotiateAPIVersion(ctx context.Context)
NegotiateAPIVersionPing(types.Ping)
HijackDialer
Dialer() func(context.Context) (net.Conn, error)
Close() error
SwarmManagementAPIClient
}
// SwarmManagementAPIClient defines all methods for managing Swarm-specific
// objects.
type SwarmManagementAPIClient interface {
SwarmAPIClient
NodeAPIClient
ServiceAPIClient
SecretAPIClient
ConfigAPIClient
}
// HijackDialer defines methods for a hijack dialer.
type HijackDialer interface {
DialHijack(ctx context.Context, url, proto string, meta map[string][]string) (net.Conn, error)
}
// ContainerAPIClient defines API client methods for the containers
type ContainerAPIClient interface {
ContainerAttach(ctx context.Context, container string, options container.AttachOptions) (types.HijackedResponse, error)
ContainerCommit(ctx context.Context, container string, options container.CommitOptions) (container.CommitResponse, error)
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error)
ContainerDiff(ctx context.Context, container string) ([]container.FilesystemChange, error)
ContainerExecAttach(ctx context.Context, execID string, options container.ExecAttachOptions) (types.HijackedResponse, error)
ContainerExecCreate(ctx context.Context, container string, options container.ExecOptions) (container.ExecCreateResponse, error)
ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error)
ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error
ContainerExecStart(ctx context.Context, execID string, options container.ExecStartOptions) error
ContainerExport(ctx context.Context, container string) (io.ReadCloser, error)
ContainerInspect(ctx context.Context, container string) (container.InspectResponse, error)
ContainerInspectWithRaw(ctx context.Context, container string, getSize bool) (container.InspectResponse, []byte, error)
ContainerKill(ctx context.Context, container, signal string) error
ContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error)
ContainerLogs(ctx context.Context, container string, options container.LogsOptions) (io.ReadCloser, error)
ContainerPause(ctx context.Context, container string) error
ContainerRemove(ctx context.Context, container string, options container.RemoveOptions) error
ContainerRename(ctx context.Context, container, newContainerName string) error
ContainerResize(ctx context.Context, container string, options container.ResizeOptions) error
ContainerRestart(ctx context.Context, container string, options container.StopOptions) error
ContainerStatPath(ctx context.Context, container, path string) (container.PathStat, error)
ContainerStats(ctx context.Context, container string, stream bool) (container.StatsResponseReader, error)
ContainerStatsOneShot(ctx context.Context, container string) (container.StatsResponseReader, error)
ContainerStart(ctx context.Context, container string, options container.StartOptions) error
ContainerStop(ctx context.Context, container string, options container.StopOptions) error
ContainerTop(ctx context.Context, container string, arguments []string) (container.TopResponse, error)
ContainerUnpause(ctx context.Context, container string) error
ContainerUpdate(ctx context.Context, container string, updateConfig container.UpdateConfig) (container.UpdateResponse, error)
ContainerWait(ctx context.Context, container string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error)
CopyFromContainer(ctx context.Context, container, srcPath string) (io.ReadCloser, container.PathStat, error)
CopyToContainer(ctx context.Context, container, path string, content io.Reader, options container.CopyToContainerOptions) error
ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error)
}
// DistributionAPIClient defines API client methods for the registry
type DistributionAPIClient interface {
DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registry.DistributionInspect, error)
}
// ImageAPIClient defines API client methods for the images
type ImageAPIClient interface {
ImageBuild(ctx context.Context, context io.Reader, options build.ImageBuildOptions) (build.ImageBuildResponse, error)
BuildCachePrune(ctx context.Context, opts build.CachePruneOptions) (*build.CachePruneReport, error)
BuildCancel(ctx context.Context, id string) error
ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error)
ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error)
ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error)
ImagePull(ctx context.Context, ref string, options image.PullOptions) (io.ReadCloser, error)
ImagePush(ctx context.Context, ref string, options image.PushOptions) (io.ReadCloser, error)
ImageRemove(ctx context.Context, image string, options image.RemoveOptions) ([]image.DeleteResponse, error)
ImageSearch(ctx context.Context, term string, options registry.SearchOptions) ([]registry.SearchResult, error)
ImageTag(ctx context.Context, image, ref string) error
ImagesPrune(ctx context.Context, pruneFilter filters.Args) (image.PruneReport, error)
ImageInspect(ctx context.Context, image string, _ ...ImageInspectOption) (image.InspectResponse, error)
ImageHistory(ctx context.Context, image string, _ ...ImageHistoryOption) ([]image.HistoryResponseItem, error)
ImageLoad(ctx context.Context, input io.Reader, _ ...ImageLoadOption) (image.LoadResponse, error)
ImageSave(ctx context.Context, images []string, _ ...ImageSaveOption) (io.ReadCloser, error)
ImageAPIClientDeprecated
}
// ImageAPIClientDeprecated defines deprecated methods of the ImageAPIClient.
type ImageAPIClientDeprecated interface {
// ImageInspectWithRaw returns the image information and its raw representation.
//
// Deprecated: Use [Client.ImageInspect] instead. Raw response can be obtained using the [ImageInspectWithRawResponse] option.
ImageInspectWithRaw(ctx context.Context, image string) (image.InspectResponse, []byte, error)
}
// NetworkAPIClient defines API client methods for the networks
type NetworkAPIClient interface {
NetworkConnect(ctx context.Context, network, container string, config *network.EndpointSettings) error
NetworkCreate(ctx context.Context, name string, options network.CreateOptions) (network.CreateResponse, error)
NetworkDisconnect(ctx context.Context, network, container string, force bool) error
NetworkInspect(ctx context.Context, network string, options network.InspectOptions) (network.Inspect, error)
NetworkInspectWithRaw(ctx context.Context, network string, options network.InspectOptions) (network.Inspect, []byte, error)
NetworkList(ctx context.Context, options network.ListOptions) ([]network.Summary, error)
NetworkRemove(ctx context.Context, network string) error
NetworksPrune(ctx context.Context, pruneFilter filters.Args) (network.PruneReport, error)
}
// NodeAPIClient defines API client methods for the nodes
type NodeAPIClient interface {
NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error)
NodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error)
NodeRemove(ctx context.Context, nodeID string, options swarm.NodeRemoveOptions) error
NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error
}
// PluginAPIClient defines API client methods for the plugins
type PluginAPIClient interface {
PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error)
PluginRemove(ctx context.Context, name string, options types.PluginRemoveOptions) error
PluginEnable(ctx context.Context, name string, options types.PluginEnableOptions) error
PluginDisable(ctx context.Context, name string, options types.PluginDisableOptions) error
PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error)
PluginUpgrade(ctx context.Context, name string, options types.PluginInstallOptions) (io.ReadCloser, error)
PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error)
PluginSet(ctx context.Context, name string, args []string) error
PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error)
PluginCreate(ctx context.Context, createContext io.Reader, options types.PluginCreateOptions) error
}
// ServiceAPIClient defines API client methods for the services
type ServiceAPIClient interface {
ServiceCreate(ctx context.Context, service swarm.ServiceSpec, options swarm.ServiceCreateOptions) (swarm.ServiceCreateResponse, error)
ServiceInspectWithRaw(ctx context.Context, serviceID string, options swarm.ServiceInspectOptions) (swarm.Service, []byte, error)
ServiceList(ctx context.Context, options swarm.ServiceListOptions) ([]swarm.Service, error)
ServiceRemove(ctx context.Context, serviceID string) error
ServiceUpdate(ctx context.Context, serviceID string, version swarm.Version, service swarm.ServiceSpec, options swarm.ServiceUpdateOptions) (swarm.ServiceUpdateResponse, error)
ServiceLogs(ctx context.Context, serviceID string, options container.LogsOptions) (io.ReadCloser, error)
TaskLogs(ctx context.Context, taskID string, options container.LogsOptions) (io.ReadCloser, error)
TaskInspectWithRaw(ctx context.Context, taskID string) (swarm.Task, []byte, error)
TaskList(ctx context.Context, options swarm.TaskListOptions) ([]swarm.Task, error)
}
// SwarmAPIClient defines API client methods for the swarm
type SwarmAPIClient interface {
SwarmInit(ctx context.Context, req swarm.InitRequest) (string, error)
SwarmJoin(ctx context.Context, req swarm.JoinRequest) error
SwarmGetUnlockKey(ctx context.Context) (swarm.UnlockKeyResponse, error)
SwarmUnlock(ctx context.Context, req swarm.UnlockRequest) error
SwarmLeave(ctx context.Context, force bool) error
SwarmInspect(ctx context.Context) (swarm.Swarm, error)
SwarmUpdate(ctx context.Context, version swarm.Version, swarm swarm.Spec, flags swarm.UpdateFlags) error
}
// SystemAPIClient defines API client methods for the system
type SystemAPIClient interface {
Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error)
Info(ctx context.Context) (system.Info, error)
RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error)
DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error)
Ping(ctx context.Context) (types.Ping, error)
}
// VolumeAPIClient defines API client methods for the volumes
type VolumeAPIClient interface {
VolumeCreate(ctx context.Context, options volume.CreateOptions) (volume.Volume, error)
VolumeInspect(ctx context.Context, volumeID string) (volume.Volume, error)
VolumeInspectWithRaw(ctx context.Context, volumeID string) (volume.Volume, []byte, error)
VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error)
VolumeRemove(ctx context.Context, volumeID string, force bool) error
VolumesPrune(ctx context.Context, pruneFilter filters.Args) (volume.PruneReport, error)
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
}
// SecretAPIClient defines API client methods for secrets
type SecretAPIClient interface {
SecretList(ctx context.Context, options swarm.SecretListOptions) ([]swarm.Secret, error)
SecretCreate(ctx context.Context, secret swarm.SecretSpec) (swarm.SecretCreateResponse, error)
SecretRemove(ctx context.Context, id string) error
SecretInspectWithRaw(ctx context.Context, name string) (swarm.Secret, []byte, error)
SecretUpdate(ctx context.Context, id string, version swarm.Version, secret swarm.SecretSpec) error
}
// ConfigAPIClient defines API client methods for configs
type ConfigAPIClient interface {
ConfigList(ctx context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error)
ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (swarm.ConfigCreateResponse, error)
ConfigRemove(ctx context.Context, id string) error
ConfigInspectWithRaw(ctx context.Context, name string) (swarm.Config, []byte, error)
ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error
}

View File

@@ -1,24 +0,0 @@
package client
import (
"context"
"encoding/json"
"github.com/docker/docker/api/types/swarm"
)
// ConfigCreate creates a new config.
func (cli *Client) ConfigCreate(ctx context.Context, config swarm.ConfigSpec) (swarm.ConfigCreateResponse, error) {
var response swarm.ConfigCreateResponse
if err := cli.NewVersionError(ctx, "1.30", "config create"); err != nil {
return response, err
}
resp, err := cli.post(ctx, "/configs/create", nil, config, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@@ -1,37 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"github.com/docker/docker/api/types/swarm"
)
// ConfigInspectWithRaw returns the config information with raw data
func (cli *Client) ConfigInspectWithRaw(ctx context.Context, id string) (swarm.Config, []byte, error) {
id, err := trimID("contig", id)
if err != nil {
return swarm.Config{}, nil, err
}
if err := cli.NewVersionError(ctx, "1.30", "config inspect"); err != nil {
return swarm.Config{}, nil, err
}
resp, err := cli.get(ctx, "/configs/"+id, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Config{}, nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Config{}, nil, err
}
var config swarm.Config
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&config)
return config, body, err
}

View File

@@ -1,37 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
)
// ConfigList returns the list of configs.
func (cli *Client) ConfigList(ctx context.Context, options swarm.ConfigListOptions) ([]swarm.Config, error) {
if err := cli.NewVersionError(ctx, "1.30", "config list"); err != nil {
return nil, err
}
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/configs", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var configs []swarm.Config
err = json.NewDecoder(resp.Body).Decode(&configs)
return configs, err
}

View File

@@ -1,17 +0,0 @@
package client
import "context"
// ConfigRemove removes a config.
func (cli *Client) ConfigRemove(ctx context.Context, id string) error {
id, err := trimID("config", id)
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.30", "config remove"); err != nil {
return err
}
resp, err := cli.delete(ctx, "/configs/"+id, nil, nil)
defer ensureReaderClosed(resp)
return err
}

View File

@@ -1,24 +0,0 @@
package client
import (
"context"
"net/url"
"github.com/docker/docker/api/types/swarm"
)
// ConfigUpdate attempts to update a config
func (cli *Client) ConfigUpdate(ctx context.Context, id string, version swarm.Version, config swarm.ConfigSpec) error {
id, err := trimID("config", id)
if err != nil {
return err
}
if err := cli.NewVersionError(ctx, "1.30", "config update"); err != nil {
return err
}
query := url.Values{}
query.Set("version", version.String())
resp, err := cli.post(ctx, "/configs/"+id+"/update", query, config, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,65 +0,0 @@
package client
import (
"context"
"net/http"
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
)
// ContainerAttach attaches a connection to a container in the server.
// It returns a types.HijackedConnection with the hijacked connection
// and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close.
//
// The stream format on the response will be in one of two formats:
//
// If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// multiplexing or headers.
//
// If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
// The format of the multiplexed stream is as follows:
//
// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
//
// STREAM_TYPE can be 1 for stdout and 2 for stderr
//
// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian.
// This is the size of OUTPUT.
//
// You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this
// stream.
func (cli *Client) ContainerAttach(ctx context.Context, containerID string, options container.AttachOptions) (types.HijackedResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return types.HijackedResponse{}, err
}
query := url.Values{}
if options.Stream {
query.Set("stream", "1")
}
if options.Stdin {
query.Set("stdin", "1")
}
if options.Stdout {
query.Set("stdout", "1")
}
if options.Stderr {
query.Set("stderr", "1")
}
if options.DetachKeys != "" {
query.Set("detachKeys", options.DetachKeys)
}
if options.Logs {
query.Set("logs", "1")
}
return cli.postHijacked(ctx, "/containers/"+containerID+"/attach", query, nil, http.Header{
"Content-Type": {"text/plain"},
})
}

View File

@@ -1,168 +0,0 @@
package client
import (
"context"
"encoding/json"
"errors"
"net/url"
"path"
"sort"
"strings"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ContainerCreate creates a new container based on the given configuration.
// It can be associated with a name, but it's not mandatory.
func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *ocispec.Platform, containerName string) (container.CreateResponse, error) {
var response container.CreateResponse
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.41", "specify container image platform"); platform != nil && err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.44", "specify health-check start interval"); config != nil && config.Healthcheck != nil && config.Healthcheck.StartInterval != 0 && err != nil {
return response, err
}
if err := cli.NewVersionError(ctx, "1.44", "specify mac-address per network"); hasEndpointSpecificMacAddress(networkingConfig) && err != nil {
return response, err
}
if hostConfig != nil {
if versions.LessThan(cli.ClientVersion(), "1.25") {
// When using API 1.24 and under, the client is responsible for removing the container
hostConfig.AutoRemove = false
}
if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.42") || versions.LessThan(cli.ClientVersion(), "1.40") {
// KernelMemory was added in API 1.40, and deprecated in API 1.42
hostConfig.KernelMemory = 0
}
if platform != nil && platform.OS == "linux" && versions.LessThan(cli.ClientVersion(), "1.42") {
// When using API under 1.42, the Linux daemon doesn't respect the ConsoleSize
hostConfig.ConsoleSize = [2]uint{0, 0}
}
if versions.LessThan(cli.ClientVersion(), "1.44") {
for _, m := range hostConfig.Mounts {
if m.BindOptions != nil {
// ReadOnlyNonRecursive can be safely ignored when API < 1.44
if m.BindOptions.ReadOnlyForceRecursive {
return response, errors.New("bind-recursive=readonly requires API v1.44 or later")
}
if m.BindOptions.NonRecursive && versions.LessThan(cli.ClientVersion(), "1.40") {
return response, errors.New("bind-recursive=disabled requires API v1.40 or later")
}
}
}
}
hostConfig.CapAdd = normalizeCapabilities(hostConfig.CapAdd)
hostConfig.CapDrop = normalizeCapabilities(hostConfig.CapDrop)
}
// Since API 1.44, the container-wide MacAddress is deprecated and will trigger a WARNING if it's specified.
if versions.GreaterThanOrEqualTo(cli.ClientVersion(), "1.44") {
config.MacAddress = "" //nolint:staticcheck // ignore SA1019: field is deprecated, but still used on API < v1.44.
}
query := url.Values{}
if p := formatPlatform(platform); p != "" {
query.Set("platform", p)
}
if containerName != "" {
query.Set("name", containerName)
}
body := container.CreateRequest{
Config: config,
HostConfig: hostConfig,
NetworkingConfig: networkingConfig,
}
resp, err := cli.post(ctx, "/containers/create", query, body, nil)
defer ensureReaderClosed(resp)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}
// formatPlatform returns a formatted string representing platform (e.g. linux/arm/v7).
//
// Similar to containerd's platforms.Format(), but does allow components to be
// omitted (e.g. pass "architecture" only, without "os":
// https://github.com/containerd/containerd/blob/v1.5.2/platforms/platforms.go#L243-L263
func formatPlatform(platform *ocispec.Platform) string {
if platform == nil {
return ""
}
return path.Join(platform.OS, platform.Architecture, platform.Variant)
}
// hasEndpointSpecificMacAddress checks whether one of the endpoint in networkingConfig has a MacAddress defined.
func hasEndpointSpecificMacAddress(networkingConfig *network.NetworkingConfig) bool {
if networkingConfig == nil {
return false
}
for _, endpoint := range networkingConfig.EndpointsConfig {
if endpoint.MacAddress != "" {
return true
}
}
return false
}
// allCapabilities is a magic value for "all capabilities"
const allCapabilities = "ALL"
// normalizeCapabilities normalizes capabilities to their canonical form,
// removes duplicates, and sorts the results.
//
// It is similar to [github.com/docker/docker/oci/caps.NormalizeLegacyCapabilities],
// but performs no validation based on supported capabilities.
func normalizeCapabilities(caps []string) []string {
var normalized []string
unique := make(map[string]struct{})
for _, c := range caps {
c = normalizeCap(c)
if _, ok := unique[c]; ok {
continue
}
unique[c] = struct{}{}
normalized = append(normalized, c)
}
sort.Strings(normalized)
return normalized
}
// normalizeCap normalizes a capability to its canonical format by upper-casing
// and adding a "CAP_" prefix (if not yet present). It also accepts the "ALL"
// magic-value.
func normalizeCap(cap string) string {
cap = strings.ToUpper(cap)
if cap == allCapabilities {
return cap
}
if !strings.HasPrefix(cap, "CAP_") {
cap = "CAP_" + cap
}
return cap
}

View File

@@ -1,81 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/http"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions"
)
// ContainerExecCreate creates a new exec configuration to run an exec process.
func (cli *Client) ContainerExecCreate(ctx context.Context, containerID string, options container.ExecOptions) (container.ExecCreateResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.ExecCreateResponse{}, err
}
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return container.ExecCreateResponse{}, err
}
if err := cli.NewVersionError(ctx, "1.25", "env"); len(options.Env) != 0 && err != nil {
return container.ExecCreateResponse{}, err
}
if versions.LessThan(cli.ClientVersion(), "1.42") {
options.ConsoleSize = nil
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/exec", nil, options, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.ExecCreateResponse{}, err
}
var response container.ExecCreateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}
// ContainerExecStart starts an exec process already created in the docker host.
func (cli *Client) ContainerExecStart(ctx context.Context, execID string, config container.ExecStartOptions) error {
if versions.LessThan(cli.ClientVersion(), "1.42") {
config.ConsoleSize = nil
}
resp, err := cli.post(ctx, "/exec/"+execID+"/start", nil, config, nil)
ensureReaderClosed(resp)
return err
}
// ContainerExecAttach attaches a connection to an exec process in the server.
// It returns a types.HijackedConnection with the hijacked connection
// and the a reader to get output. It's up to the called to close
// the hijacked connection by calling types.HijackedResponse.Close.
func (cli *Client) ContainerExecAttach(ctx context.Context, execID string, config container.ExecAttachOptions) (types.HijackedResponse, error) {
if versions.LessThan(cli.ClientVersion(), "1.42") {
config.ConsoleSize = nil
}
return cli.postHijacked(ctx, "/exec/"+execID+"/start", nil, config, http.Header{
"Content-Type": {"application/json"},
})
}
// ContainerExecInspect returns information about a specific exec process on the docker host.
func (cli *Client) ContainerExecInspect(ctx context.Context, execID string) (container.ExecInspect, error) {
var response container.ExecInspect
resp, err := cli.get(ctx, "/exec/"+execID+"/json", nil, nil)
if err != nil {
return response, err
}
err = json.NewDecoder(resp.Body).Decode(&response)
ensureReaderClosed(resp)
return response, err
}

View File

@@ -1,24 +0,0 @@
package client
import (
"context"
"io"
"net/url"
)
// ContainerExport retrieves the raw contents of a container
// and returns them as an io.ReadCloser. It's up to the caller
// to close the stream.
func (cli *Client) ContainerExport(ctx context.Context, containerID string) (io.ReadCloser, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return nil, err
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/export", url.Values{}, nil)
if err != nil {
return nil, err
}
return resp.Body, nil
}

View File

@@ -1,57 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"net/url"
"github.com/docker/docker/api/types/container"
)
// ContainerInspect returns the container information.
func (cli *Client) ContainerInspect(ctx context.Context, containerID string) (container.InspectResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.InspectResponse{}, err
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/json", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.InspectResponse{}, err
}
var response container.InspectResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}
// ContainerInspectWithRaw returns the container information and its raw representation.
func (cli *Client) ContainerInspectWithRaw(ctx context.Context, containerID string, getSize bool) (container.InspectResponse, []byte, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.InspectResponse{}, nil, err
}
query := url.Values{}
if getSize {
query.Set("size", "1")
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.InspectResponse{}, nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return container.InspectResponse{}, nil, err
}
var response container.InspectResponse
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&response)
return response, body, err
}

View File

@@ -1,23 +0,0 @@
package client
import (
"context"
"net/url"
)
// ContainerKill terminates the container process but does not remove the container from the docker host.
func (cli *Client) ContainerKill(ctx context.Context, containerID, signal string) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
query := url.Values{}
if signal != "" {
query.Set("signal", signal)
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/kill", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,56 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"strconv"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
)
// ContainerList returns the list of containers in the docker host.
func (cli *Client) ContainerList(ctx context.Context, options container.ListOptions) ([]container.Summary, error) {
query := url.Values{}
if options.All {
query.Set("all", "1")
}
if options.Limit > 0 {
query.Set("limit", strconv.Itoa(options.Limit))
}
if options.Since != "" {
query.Set("since", options.Since)
}
if options.Before != "" {
query.Set("before", options.Before)
}
if options.Size {
query.Set("size", "1")
}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/containers/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var containers []container.Summary
err = json.NewDecoder(resp.Body).Decode(&containers)
return containers, err
}

View File

@@ -1,85 +0,0 @@
package client
import (
"context"
"io"
"net/url"
"time"
"github.com/docker/docker/api/types/container"
timetypes "github.com/docker/docker/api/types/time"
"github.com/pkg/errors"
)
// ContainerLogs returns the logs generated by a container in an io.ReadCloser.
// It's up to the caller to close the stream.
//
// The stream format on the response will be in one of two formats:
//
// If the container is using a TTY, there is only a single stream (stdout), and
// data is copied directly from the container output stream, no extra
// multiplexing or headers.
//
// If the container is *not* using a TTY, streams for stdout and stderr are
// multiplexed.
// The format of the multiplexed stream is as follows:
//
// [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}[]byte{OUTPUT}
//
// STREAM_TYPE can be 1 for stdout and 2 for stderr
//
// SIZE1, SIZE2, SIZE3, and SIZE4 are four bytes of uint32 encoded as big endian.
// This is the size of OUTPUT.
//
// You can use github.com/docker/docker/pkg/stdcopy.StdCopy to demultiplex this
// stream.
func (cli *Client) ContainerLogs(ctx context.Context, containerID string, options container.LogsOptions) (io.ReadCloser, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return nil, err
}
query := url.Values{}
if options.ShowStdout {
query.Set("stdout", "1")
}
if options.ShowStderr {
query.Set("stderr", "1")
}
if options.Since != "" {
ts, err := timetypes.GetTimestamp(options.Since, time.Now())
if err != nil {
return nil, errors.Wrap(err, `invalid value for "since"`)
}
query.Set("since", ts)
}
if options.Until != "" {
ts, err := timetypes.GetTimestamp(options.Until, time.Now())
if err != nil {
return nil, errors.Wrap(err, `invalid value for "until"`)
}
query.Set("until", ts)
}
if options.Timestamps {
query.Set("timestamps", "1")
}
if options.Details {
query.Set("details", "1")
}
if options.Follow {
query.Set("follow", "1")
}
query.Set("tail", options.Tail)
resp, err := cli.get(ctx, "/containers/"+containerID+"/logs", query, nil)
if err != nil {
return nil, err
}
return resp.Body, nil
}

View File

@@ -1,15 +0,0 @@
package client
import "context"
// ContainerPause pauses the main process of a given container without terminating it.
func (cli *Client) ContainerPause(ctx context.Context, containerID string) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/pause", nil, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,35 +0,0 @@
package client
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
)
// ContainersPrune requests the daemon to delete unused data
func (cli *Client) ContainersPrune(ctx context.Context, pruneFilters filters.Args) (container.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "container prune"); err != nil {
return container.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return container.PruneReport{}, err
}
resp, err := cli.post(ctx, "/containers/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.PruneReport{}, err
}
var report container.PruneReport
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return container.PruneReport{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return report, nil
}

View File

@@ -1,20 +0,0 @@
package client
import (
"context"
"net/url"
)
// ContainerRename changes the name of a given container.
func (cli *Client) ContainerRename(ctx context.Context, containerID, newContainerName string) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
query := url.Values{}
query.Set("name", newContainerName)
resp, err := cli.post(ctx, "/containers/"+containerID+"/rename", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,38 +0,0 @@
package client
import (
"context"
"net/url"
"strconv"
"github.com/docker/docker/api/types/container"
)
// ContainerResize changes the size of the tty for a container.
func (cli *Client) ContainerResize(ctx context.Context, containerID string, options container.ResizeOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
return cli.resize(ctx, "/containers/"+containerID, options.Height, options.Width)
}
// ContainerExecResize changes the size of the tty for an exec process running inside a container.
func (cli *Client) ContainerExecResize(ctx context.Context, execID string, options container.ResizeOptions) error {
execID, err := trimID("exec", execID)
if err != nil {
return err
}
return cli.resize(ctx, "/exec/"+execID, options.Height, options.Width)
}
func (cli *Client) resize(ctx context.Context, basePath string, height, width uint) error {
// FIXME(thaJeztah): the API / backend accepts uint32, but container.ResizeOptions uses uint.
query := url.Values{}
query.Set("h", strconv.FormatUint(uint64(height), 10))
query.Set("w", strconv.FormatUint(uint64(width), 10))
resp, err := cli.post(ctx, basePath+"/resize", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,41 +0,0 @@
package client
import (
"context"
"net/url"
"strconv"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions"
)
// ContainerRestart stops and starts a container again.
// It makes the daemon wait for the container to be up again for
// a specific amount of time, given the timeout.
func (cli *Client) ContainerRestart(ctx context.Context, containerID string, options container.StopOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
query := url.Values{}
if options.Timeout != nil {
query.Set("t", strconv.Itoa(*options.Timeout))
}
if options.Signal != "" {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
if versions.GreaterThanOrEqualTo(cli.version, "1.42") {
query.Set("signal", options.Signal)
}
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/restart", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,56 +0,0 @@
package client
import (
"context"
"net/url"
"github.com/docker/docker/api/types/container"
)
// ContainerStats returns near realtime stats for a given container.
// It's up to the caller to close the io.ReadCloser returned.
func (cli *Client) ContainerStats(ctx context.Context, containerID string, stream bool) (container.StatsResponseReader, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.StatsResponseReader{}, err
}
query := url.Values{}
query.Set("stream", "0")
if stream {
query.Set("stream", "1")
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
if err != nil {
return container.StatsResponseReader{}, err
}
return container.StatsResponseReader{
Body: resp.Body,
OSType: resp.Header.Get("Ostype"),
}, nil
}
// ContainerStatsOneShot gets a single stat entry from a container.
// It differs from `ContainerStats` in that the API should not wait to prime the stats
func (cli *Client) ContainerStatsOneShot(ctx context.Context, containerID string) (container.StatsResponseReader, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.StatsResponseReader{}, err
}
query := url.Values{}
query.Set("stream", "0")
query.Set("one-shot", "1")
resp, err := cli.get(ctx, "/containers/"+containerID+"/stats", query, nil)
if err != nil {
return container.StatsResponseReader{}, err
}
return container.StatsResponseReader{
Body: resp.Body,
OSType: resp.Header.Get("Ostype"),
}, nil
}

View File

@@ -1,45 +0,0 @@
package client
import (
"context"
"net/url"
"strconv"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions"
)
// ContainerStop stops a container. In case the container fails to stop
// gracefully within a time frame specified by the timeout argument,
// it is forcefully terminated (killed).
//
// If the timeout is nil, the container's StopTimeout value is used, if set,
// otherwise the engine default. A negative timeout value can be specified,
// meaning no timeout, i.e. no forceful termination is performed.
func (cli *Client) ContainerStop(ctx context.Context, containerID string, options container.StopOptions) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
query := url.Values{}
if options.Timeout != nil {
query.Set("t", strconv.Itoa(*options.Timeout))
}
if options.Signal != "" {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return err
}
if versions.GreaterThanOrEqualTo(cli.version, "1.42") {
query.Set("signal", options.Signal)
}
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/stop", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,33 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"strings"
"github.com/docker/docker/api/types/container"
)
// ContainerTop shows process information from within a container.
func (cli *Client) ContainerTop(ctx context.Context, containerID string, arguments []string) (container.TopResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.TopResponse{}, err
}
query := url.Values{}
if len(arguments) > 0 {
query.Set("ps_args", strings.Join(arguments, " "))
}
resp, err := cli.get(ctx, "/containers/"+containerID+"/top", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.TopResponse{}, err
}
var response container.TopResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@@ -1,15 +0,0 @@
package client
import "context"
// ContainerUnpause resumes the process execution within a container
func (cli *Client) ContainerUnpause(ctx context.Context, containerID string) error {
containerID, err := trimID("container", containerID)
if err != nil {
return err
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/unpause", nil, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,26 +0,0 @@
package client
import (
"context"
"encoding/json"
"github.com/docker/docker/api/types/container"
)
// ContainerUpdate updates the resources of a container.
func (cli *Client) ContainerUpdate(ctx context.Context, containerID string, updateConfig container.UpdateConfig) (container.UpdateResponse, error) {
containerID, err := trimID("container", containerID)
if err != nil {
return container.UpdateResponse{}, err
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/update", nil, updateConfig, nil)
defer ensureReaderClosed(resp)
if err != nil {
return container.UpdateResponse{}, err
}
var response container.UpdateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@@ -1,122 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"errors"
"io"
"net/url"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/versions"
)
const containerWaitErrorMsgLimit = 2 * 1024 /* Max: 2KiB */
// ContainerWait waits until the specified container is in a certain state
// indicated by the given condition, either "not-running" (default),
// "next-exit", or "removed".
//
// If this client's API version is before 1.30, condition is ignored and
// ContainerWait will return immediately with the two channels, as the server
// will wait as if the condition were "not-running".
//
// If this client's API version is at least 1.30, ContainerWait blocks until
// the request has been acknowledged by the server (with a response header),
// then returns two channels on which the caller can wait for the exit status
// of the container or an error if there was a problem either beginning the
// wait request or in getting the response. This allows the caller to
// synchronize ContainerWait with other calls, such as specifying a
// "next-exit" condition before issuing a ContainerStart request.
func (cli *Client) ContainerWait(ctx context.Context, containerID string, condition container.WaitCondition) (<-chan container.WaitResponse, <-chan error) {
resultC := make(chan container.WaitResponse)
errC := make(chan error, 1)
containerID, err := trimID("container", containerID)
if err != nil {
errC <- err
return resultC, errC
}
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
errC <- err
return resultC, errC
}
if versions.LessThan(cli.ClientVersion(), "1.30") {
return cli.legacyContainerWait(ctx, containerID)
}
query := url.Values{}
if condition != "" {
query.Set("condition", string(condition))
}
resp, err := cli.post(ctx, "/containers/"+containerID+"/wait", query, nil, nil)
if err != nil {
defer ensureReaderClosed(resp)
errC <- err
return resultC, errC
}
go func() {
defer ensureReaderClosed(resp)
responseText := bytes.NewBuffer(nil)
stream := io.TeeReader(resp.Body, responseText)
var res container.WaitResponse
if err := json.NewDecoder(stream).Decode(&res); err != nil {
// NOTE(nicks): The /wait API does not work well with HTTP proxies.
// At any time, the proxy could cut off the response stream.
//
// But because the HTTP status has already been written, the proxy's
// only option is to write a plaintext error message.
//
// If there's a JSON parsing error, read the real error message
// off the body and send it to the client.
if errors.As(err, new(*json.SyntaxError)) {
_, _ = io.ReadAll(io.LimitReader(stream, containerWaitErrorMsgLimit))
errC <- errors.New(responseText.String())
} else {
errC <- err
}
return
}
resultC <- res
}()
return resultC, errC
}
// legacyContainerWait returns immediately and doesn't have an option to wait
// until the container is removed.
func (cli *Client) legacyContainerWait(ctx context.Context, containerID string) (<-chan container.WaitResponse, <-chan error) {
resultC := make(chan container.WaitResponse)
errC := make(chan error)
go func() {
resp, err := cli.post(ctx, "/containers/"+containerID+"/wait", nil, nil, nil)
if err != nil {
errC <- err
return
}
defer ensureReaderClosed(resp)
var res container.WaitResponse
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
errC <- err
return
}
resultC <- res
}()
return resultC, errC
}

View File

@@ -1,33 +0,0 @@
package client
import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/docker/docker/api/types"
)
// DiskUsage requests the current data usage from the daemon
func (cli *Client) DiskUsage(ctx context.Context, options types.DiskUsageOptions) (types.DiskUsage, error) {
var query url.Values
if len(options.Types) > 0 {
query = url.Values{}
for _, t := range options.Types {
query.Add("type", string(t))
}
}
resp, err := cli.get(ctx, "/system/df", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return types.DiskUsage{}, err
}
var du types.DiskUsage
if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
return types.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return du, nil
}

View File

@@ -1,39 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/http"
"net/url"
"github.com/docker/docker/api/types/registry"
)
// DistributionInspect returns the image digest with the full manifest.
func (cli *Client) DistributionInspect(ctx context.Context, imageRef, encodedRegistryAuth string) (registry.DistributionInspect, error) {
if imageRef == "" {
return registry.DistributionInspect{}, objectNotFoundError{object: "distribution", id: imageRef}
}
if err := cli.NewVersionError(ctx, "1.30", "distribution inspect"); err != nil {
return registry.DistributionInspect{}, err
}
var headers http.Header
if encodedRegistryAuth != "" {
headers = http.Header{
registry.AuthHeader: {encodedRegistryAuth},
}
}
// Contact the registry to retrieve digest and platform information
resp, err := cli.get(ctx, "/distribution/"+imageRef+"/json", url.Values{}, headers)
defer ensureReaderClosed(resp)
if err != nil {
return registry.DistributionInspect{}, err
}
var distributionInspect registry.DistributionInspect
err = json.NewDecoder(resp.Body).Decode(&distributionInspect)
return distributionInspect, err
}

View File

@@ -1,100 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"time"
"github.com/docker/docker/api/types/events"
"github.com/docker/docker/api/types/filters"
timetypes "github.com/docker/docker/api/types/time"
)
// Events returns a stream of events in the daemon. It's up to the caller to close the stream
// by cancelling the context. Once the stream has been completely read an io.EOF error will
// be sent over the error channel. If an error is sent all processing will be stopped. It's up
// to the caller to reopen the stream in the event of an error by reinvoking this method.
func (cli *Client) Events(ctx context.Context, options events.ListOptions) (<-chan events.Message, <-chan error) {
messages := make(chan events.Message)
errs := make(chan error, 1)
started := make(chan struct{})
go func() {
defer close(errs)
query, err := buildEventsQueryParams(cli.version, options)
if err != nil {
close(started)
errs <- err
return
}
resp, err := cli.get(ctx, "/events", query, nil)
if err != nil {
close(started)
errs <- err
return
}
defer resp.Body.Close()
decoder := json.NewDecoder(resp.Body)
close(started)
for {
select {
case <-ctx.Done():
errs <- ctx.Err()
return
default:
var event events.Message
if err := decoder.Decode(&event); err != nil {
errs <- err
return
}
select {
case messages <- event:
case <-ctx.Done():
errs <- ctx.Err()
return
}
}
}
}()
<-started
return messages, errs
}
func buildEventsQueryParams(cliVersion string, options events.ListOptions) (url.Values, error) {
query := url.Values{}
ref := time.Now()
if options.Since != "" {
ts, err := timetypes.GetTimestamp(options.Since, ref)
if err != nil {
return nil, err
}
query.Set("since", ts)
}
if options.Until != "" {
ts, err := timetypes.GetTimestamp(options.Until, ref)
if err != nil {
return nil, err
}
query.Set("until", ts)
}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cliVersion, options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
return query, nil
}

View File

@@ -1,40 +0,0 @@
package client
import (
"context"
"io"
"net/http"
"net/url"
"strings"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/registry"
)
// ImageCreate creates a new image based on the parent options.
// It returns the JSON content in the response body.
func (cli *Client) ImageCreate(ctx context.Context, parentReference string, options image.CreateOptions) (io.ReadCloser, error) {
ref, err := reference.ParseNormalizedNamed(parentReference)
if err != nil {
return nil, err
}
query := url.Values{}
query.Set("fromImage", ref.Name())
query.Set("tag", getAPITagFromNamedRef(ref))
if options.Platform != "" {
query.Set("platform", strings.ToLower(options.Platform))
}
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
if err != nil {
return nil, err
}
return resp.Body, nil
}
func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/images/create", query, nil, http.Header{
registry.AuthHeader: {registryAuth},
})
}

View File

@@ -1,48 +0,0 @@
package client
import (
"context"
"io"
"net/url"
"strings"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
)
// ImageImport creates a new image based on the source options.
// It returns the JSON content in the response body.
func (cli *Client) ImageImport(ctx context.Context, source image.ImportSource, ref string, options image.ImportOptions) (io.ReadCloser, error) {
if ref != "" {
// Check if the given image name can be resolved
if _, err := reference.ParseNormalizedNamed(ref); err != nil {
return nil, err
}
}
query := url.Values{}
if source.SourceName != "" {
query.Set("fromSrc", source.SourceName)
}
if ref != "" {
query.Set("repo", ref)
}
if options.Tag != "" {
query.Set("tag", options.Tag)
}
if options.Message != "" {
query.Set("message", options.Message)
}
if options.Platform != "" {
query.Set("platform", strings.ToLower(options.Platform))
}
for _, change := range options.Changes {
query.Add("changes", change)
}
resp, err := cli.postRaw(ctx, "/images/create", query, source.Source, nil)
if err != nil {
return nil, err
}
return resp.Body, nil
}

View File

@@ -1,76 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"net/url"
"github.com/docker/docker/api/types/image"
)
// ImageInspect returns the image information.
func (cli *Client) ImageInspect(ctx context.Context, imageID string, inspectOpts ...ImageInspectOption) (image.InspectResponse, error) {
if imageID == "" {
return image.InspectResponse{}, objectNotFoundError{object: "image", id: imageID}
}
var opts imageInspectOpts
for _, opt := range inspectOpts {
if err := opt.Apply(&opts); err != nil {
return image.InspectResponse{}, fmt.Errorf("error applying image inspect option: %w", err)
}
}
query := url.Values{}
if opts.apiOptions.Manifests {
if err := cli.NewVersionError(ctx, "1.48", "manifests"); err != nil {
return image.InspectResponse{}, err
}
query.Set("manifests", "1")
}
if opts.apiOptions.Platform != nil {
if err := cli.NewVersionError(ctx, "1.49", "platform"); err != nil {
return image.InspectResponse{}, err
}
platform, err := encodePlatform(opts.apiOptions.Platform)
if err != nil {
return image.InspectResponse{}, err
}
query.Set("platform", platform)
}
resp, err := cli.get(ctx, "/images/"+imageID+"/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return image.InspectResponse{}, err
}
buf := opts.raw
if buf == nil {
buf = &bytes.Buffer{}
}
if _, err := io.Copy(buf, resp.Body); err != nil {
return image.InspectResponse{}, err
}
var response image.InspectResponse
err = json.Unmarshal(buf.Bytes(), &response)
return response, err
}
// ImageInspectWithRaw returns the image information and its raw representation.
//
// Deprecated: Use [Client.ImageInspect] instead. Raw response can be obtained using the [ImageInspectWithRawResponse] option.
func (cli *Client) ImageInspectWithRaw(ctx context.Context, imageID string) (image.InspectResponse, []byte, error) {
var buf bytes.Buffer
resp, err := cli.ImageInspect(ctx, imageID, ImageInspectWithRawResponse(&buf))
if err != nil {
return image.InspectResponse{}, nil, err
}
return resp, buf.Bytes(), err
}

View File

@@ -1,67 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/api/types/versions"
)
// ImageList returns a list of images in the docker host.
//
// Experimental: Setting the [options.Manifest] will populate
// [image.Summary.Manifests] with information about image manifests.
// This is experimental and might change in the future without any backward
// compatibility.
func (cli *Client) ImageList(ctx context.Context, options image.ListOptions) ([]image.Summary, error) {
var images []image.Summary
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return images, err
}
query := url.Values{}
optionFilters := options.Filters
referenceFilters := optionFilters.Get("reference")
if versions.LessThan(cli.version, "1.25") && len(referenceFilters) > 0 {
query.Set("filter", referenceFilters[0])
for _, filterValue := range referenceFilters {
optionFilters.Del("reference", filterValue)
}
}
if optionFilters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, optionFilters)
if err != nil {
return images, err
}
query.Set("filters", filterJSON)
}
if options.All {
query.Set("all", "1")
}
if options.SharedSize && versions.GreaterThanOrEqualTo(cli.version, "1.42") {
query.Set("shared-size", "1")
}
if options.Manifests && versions.GreaterThanOrEqualTo(cli.version, "1.47") {
query.Set("manifests", "1")
}
resp, err := cli.get(ctx, "/images/json", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return images, err
}
err = json.NewDecoder(resp.Body).Decode(&images)
return images, err
}

View File

@@ -1,54 +0,0 @@
package client
import (
"context"
"io"
"net/http"
"net/url"
"github.com/docker/docker/api/types/image"
)
// ImageLoad loads an image in the docker host from the client host.
// It's up to the caller to close the io.ReadCloser in the
// ImageLoadResponse returned by this function.
//
// Platform is an optional parameter that specifies the platform to load from
// the provided multi-platform image. This is only has effect if the input image
// is a multi-platform image.
func (cli *Client) ImageLoad(ctx context.Context, input io.Reader, loadOpts ...ImageLoadOption) (image.LoadResponse, error) {
var opts imageLoadOpts
for _, opt := range loadOpts {
if err := opt.Apply(&opts); err != nil {
return image.LoadResponse{}, err
}
}
query := url.Values{}
query.Set("quiet", "0")
if opts.apiOptions.Quiet {
query.Set("quiet", "1")
}
if len(opts.apiOptions.Platforms) > 0 {
if err := cli.NewVersionError(ctx, "1.48", "platform"); err != nil {
return image.LoadResponse{}, err
}
p, err := encodePlatforms(opts.apiOptions.Platforms...)
if err != nil {
return image.LoadResponse{}, err
}
query["platform"] = p
}
resp, err := cli.postRaw(ctx, "/images/load", query, input, http.Header{
"Content-Type": {"application/x-tar"},
})
if err != nil {
return image.LoadResponse{}, err
}
return image.LoadResponse{
Body: resp.Body,
JSON: resp.Header.Get("Content-Type") == "application/json",
}, nil
}

View File

@@ -1,35 +0,0 @@
package client
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/image"
)
// ImagesPrune requests the daemon to delete unused data
func (cli *Client) ImagesPrune(ctx context.Context, pruneFilters filters.Args) (image.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "image prune"); err != nil {
return image.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return image.PruneReport{}, err
}
resp, err := cli.post(ctx, "/images/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return image.PruneReport{}, err
}
var report image.PruneReport
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return image.PruneReport{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return report, nil
}

View File

@@ -1,64 +0,0 @@
package client
import (
"context"
"io"
"net/url"
"strings"
cerrdefs "github.com/containerd/errdefs"
"github.com/distribution/reference"
"github.com/docker/docker/api/types/image"
)
// ImagePull requests the docker host to pull an image from a remote registry.
// It executes the privileged function if the operation is unauthorized
// and it tries one more time.
// It's up to the caller to handle the io.ReadCloser and close it properly.
//
// FIXME(vdemeester): there is currently used in a few way in docker/docker
// - if not in trusted content, ref is used to pass the whole reference, and tag is empty
// - if in trusted content, ref is used to pass the reference name, and tag for the digest
func (cli *Client) ImagePull(ctx context.Context, refStr string, options image.PullOptions) (io.ReadCloser, error) {
ref, err := reference.ParseNormalizedNamed(refStr)
if err != nil {
return nil, err
}
query := url.Values{}
query.Set("fromImage", ref.Name())
if !options.All {
query.Set("tag", getAPITagFromNamedRef(ref))
}
if options.Platform != "" {
query.Set("platform", strings.ToLower(options.Platform))
}
resp, err := cli.tryImageCreate(ctx, query, options.RegistryAuth)
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
return nil, privilegeErr
}
resp, err = cli.tryImageCreate(ctx, query, newAuthHeader)
}
if err != nil {
return nil, err
}
return resp.Body, nil
}
// getAPITagFromNamedRef returns a tag from the specified reference.
// This function is necessary as long as the docker "server" api expects
// digests to be sent as tags and makes a distinction between the name
// and tag/digest part of a reference.
func getAPITagFromNamedRef(ref reference.Named) string {
if digested, ok := ref.(reference.Digested); ok {
return digested.Digest().String()
}
ref = reference.TagNameOnly(ref)
if tagged, ok := ref.(reference.Tagged); ok {
return tagged.Tag()
}
return ""
}

View File

@@ -1,37 +0,0 @@
package client
import (
"context"
"net/url"
"github.com/distribution/reference"
"github.com/pkg/errors"
)
// ImageTag tags an image in the docker host
func (cli *Client) ImageTag(ctx context.Context, source, target string) error {
if _, err := reference.ParseAnyReference(source); err != nil {
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", source)
}
ref, err := reference.ParseNormalizedNamed(target)
if err != nil {
return errors.Wrapf(err, "Error parsing reference: %q is not a valid repository/tag", target)
}
if _, isCanonical := ref.(reference.Canonical); isCanonical {
return errors.New("refusing to create a tag with a digest reference")
}
ref = reference.TagNameOnly(ref)
query := url.Values{}
query.Set("repo", ref.Name())
if tagged, ok := ref.(reference.Tagged); ok {
query.Set("tag", tagged.Tag())
}
resp, err := cli.post(ctx, "/images/"+source+"/tag", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,26 +0,0 @@
package client
import (
"context"
"encoding/json"
"fmt"
"net/url"
"github.com/docker/docker/api/types/system"
)
// Info returns information about the docker server.
func (cli *Client) Info(ctx context.Context) (system.Info, error) {
var info system.Info
resp, err := cli.get(ctx, "/info", url.Values{}, nil)
defer ensureReaderClosed(resp)
if err != nil {
return info, err
}
if err := json.NewDecoder(resp.Body).Decode(&info); err != nil {
return info, fmt.Errorf("Error reading remote info: %v", err)
}
return info, nil
}

View File

@@ -1,24 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types/registry"
)
// RegistryLogin authenticates the docker server with a given docker registry.
// It returns unauthorizedError when the authentication fails.
func (cli *Client) RegistryLogin(ctx context.Context, auth registry.AuthConfig) (registry.AuthenticateOKBody, error) {
resp, err := cli.post(ctx, "/auth", url.Values{}, auth, nil)
defer ensureReaderClosed(resp)
if err != nil {
return registry.AuthenticateOKBody{}, err
}
var response registry.AuthenticateOKBody
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@@ -1,28 +0,0 @@
package client
import (
"context"
"github.com/docker/docker/api/types/network"
)
// NetworkConnect connects a container to an existent network in the docker host.
func (cli *Client) NetworkConnect(ctx context.Context, networkID, containerID string, config *network.EndpointSettings) error {
networkID, err := trimID("network", networkID)
if err != nil {
return err
}
containerID, err = trimID("container", containerID)
if err != nil {
return err
}
nc := network.ConnectOptions{
Container: containerID,
EndpointConfig: config,
}
resp, err := cli.post(ctx, "/networks/"+networkID+"/connect", nil, nc, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,40 +0,0 @@
package client
import (
"context"
"encoding/json"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
)
// NetworkCreate creates a new network in the docker host.
func (cli *Client) NetworkCreate(ctx context.Context, name string, options network.CreateOptions) (network.CreateResponse, error) {
// Make sure we negotiated (if the client is configured to do so),
// as code below contains API-version specific handling of options.
//
// Normally, version-negotiation (if enabled) would not happen until
// the API request is made.
if err := cli.checkVersion(ctx); err != nil {
return network.CreateResponse{}, err
}
networkCreateRequest := network.CreateRequest{
CreateOptions: options,
Name: name,
}
if versions.LessThan(cli.version, "1.44") {
enabled := true
networkCreateRequest.CheckDuplicate = &enabled //nolint:staticcheck // ignore SA1019: CheckDuplicate is deprecated since API v1.44.
}
resp, err := cli.post(ctx, "/networks/create", nil, networkCreateRequest, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.CreateResponse{}, err
}
var response network.CreateResponse
err = json.NewDecoder(resp.Body).Decode(&response)
return response, err
}

View File

@@ -1,28 +0,0 @@
package client
import (
"context"
"github.com/docker/docker/api/types/network"
)
// NetworkDisconnect disconnects a container from an existent network in the docker host.
func (cli *Client) NetworkDisconnect(ctx context.Context, networkID, containerID string, force bool) error {
networkID, err := trimID("network", networkID)
if err != nil {
return err
}
containerID, err = trimID("container", containerID)
if err != nil {
return err
}
nd := network.DisconnectOptions{
Container: containerID,
Force: force,
}
resp, err := cli.post(ctx, "/networks/"+networkID+"/disconnect", nil, nd, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,47 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"net/url"
"github.com/docker/docker/api/types/network"
)
// NetworkInspect returns the information for a specific network configured in the docker host.
func (cli *Client) NetworkInspect(ctx context.Context, networkID string, options network.InspectOptions) (network.Inspect, error) {
networkResource, _, err := cli.NetworkInspectWithRaw(ctx, networkID, options)
return networkResource, err
}
// NetworkInspectWithRaw returns the information for a specific network configured in the docker host and its raw representation.
func (cli *Client) NetworkInspectWithRaw(ctx context.Context, networkID string, options network.InspectOptions) (network.Inspect, []byte, error) {
networkID, err := trimID("network", networkID)
if err != nil {
return network.Inspect{}, nil, err
}
query := url.Values{}
if options.Verbose {
query.Set("verbose", "true")
}
if options.Scope != "" {
query.Set("scope", options.Scope)
}
resp, err := cli.get(ctx, "/networks/"+networkID, query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.Inspect{}, nil, err
}
raw, err := io.ReadAll(resp.Body)
if err != nil {
return network.Inspect{}, nil, err
}
var nw network.Inspect
err = json.NewDecoder(bytes.NewReader(raw)).Decode(&nw)
return nw, raw, err
}

View File

@@ -1,32 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
)
// NetworkList returns the list of networks configured in the docker host.
func (cli *Client) NetworkList(ctx context.Context, options network.ListOptions) ([]network.Summary, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
var networkResources []network.Summary
resp, err := cli.get(ctx, "/networks", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return networkResources, err
}
err = json.NewDecoder(resp.Body).Decode(&networkResources)
return networkResources, err
}

View File

@@ -1,35 +0,0 @@
package client
import (
"context"
"encoding/json"
"fmt"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/network"
)
// NetworksPrune requests the daemon to delete unused networks
func (cli *Client) NetworksPrune(ctx context.Context, pruneFilters filters.Args) (network.PruneReport, error) {
if err := cli.NewVersionError(ctx, "1.25", "network prune"); err != nil {
return network.PruneReport{}, err
}
query, err := getFiltersQuery(pruneFilters)
if err != nil {
return network.PruneReport{}, err
}
resp, err := cli.post(ctx, "/networks/prune", query, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return network.PruneReport{}, err
}
var report network.PruneReport
if err := json.NewDecoder(resp.Body).Decode(&report); err != nil {
return network.PruneReport{}, fmt.Errorf("Error retrieving network prune report: %v", err)
}
return report, nil
}

View File

@@ -1,14 +0,0 @@
package client
import "context"
// NetworkRemove removes an existent network from the docker host.
func (cli *Client) NetworkRemove(ctx context.Context, networkID string) error {
networkID, err := trimID("network", networkID)
if err != nil {
return err
}
resp, err := cli.delete(ctx, "/networks/"+networkID, nil, nil)
defer ensureReaderClosed(resp)
return err
}

View File

@@ -1,33 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"github.com/docker/docker/api/types/swarm"
)
// NodeInspectWithRaw returns the node information.
func (cli *Client) NodeInspectWithRaw(ctx context.Context, nodeID string) (swarm.Node, []byte, error) {
nodeID, err := trimID("node", nodeID)
if err != nil {
return swarm.Node{}, nil, err
}
resp, err := cli.get(ctx, "/nodes/"+nodeID, nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return swarm.Node{}, nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return swarm.Node{}, nil, err
}
var response swarm.Node
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&response)
return response, body, err
}

View File

@@ -1,34 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/swarm"
)
// NodeList returns the list of nodes.
func (cli *Client) NodeList(ctx context.Context, options swarm.NodeListOptions) ([]swarm.Node, error) {
query := url.Values{}
if options.Filters.Len() > 0 {
filterJSON, err := filters.ToJSON(options.Filters)
if err != nil {
return nil, err
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/nodes", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, err
}
var nodes []swarm.Node
err = json.NewDecoder(resp.Body).Decode(&nodes)
return nodes, err
}

View File

@@ -1,22 +0,0 @@
package client
import (
"context"
"net/url"
"github.com/docker/docker/api/types/swarm"
)
// NodeUpdate updates a Node.
func (cli *Client) NodeUpdate(ctx context.Context, nodeID string, version swarm.Version, node swarm.NodeSpec) error {
nodeID, err := trimID("node", nodeID)
if err != nil {
return err
}
query := url.Values{}
query.Set("version", version.String())
resp, err := cli.post(ctx, "/nodes/"+nodeID+"/update", query, node, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,240 +0,0 @@
package client
import (
"context"
"net"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/docker/go-connections/sockets"
"github.com/docker/go-connections/tlsconfig"
"github.com/pkg/errors"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel/trace"
)
// Opt is a configuration option to initialize a [Client].
type Opt func(*Client) error
// FromEnv configures the client with values from environment variables. It
// is the equivalent of using the [WithTLSClientConfigFromEnv], [WithHostFromEnv],
// and [WithVersionFromEnv] options.
//
// FromEnv uses the following environment variables:
//
// - DOCKER_HOST ([EnvOverrideHost]) to set the URL to the docker server.
// - DOCKER_API_VERSION ([EnvOverrideAPIVersion]) to set the version of the
// API to use, leave empty for latest.
// - DOCKER_CERT_PATH ([EnvOverrideCertPath]) to specify the directory from
// which to load the TLS certificates ("ca.pem", "cert.pem", "key.pem').
// - DOCKER_TLS_VERIFY ([EnvTLSVerify]) to enable or disable TLS verification
// (off by default).
func FromEnv(c *Client) error {
ops := []Opt{
WithTLSClientConfigFromEnv(),
WithHostFromEnv(),
WithVersionFromEnv(),
}
for _, op := range ops {
if err := op(c); err != nil {
return err
}
}
return nil
}
// WithDialContext applies the dialer to the client transport. This can be
// used to set the Timeout and KeepAlive settings of the client. It returns
// an error if the client does not have a [http.Transport] configured.
func WithDialContext(dialContext func(ctx context.Context, network, addr string) (net.Conn, error)) Opt {
return func(c *Client) error {
if transport, ok := c.client.Transport.(*http.Transport); ok {
transport.DialContext = dialContext
return nil
}
return errors.Errorf("cannot apply dialer to transport: %T", c.client.Transport)
}
}
// WithHost overrides the client host with the specified one.
func WithHost(host string) Opt {
return func(c *Client) error {
hostURL, err := ParseHostURL(host)
if err != nil {
return err
}
c.host = host
c.proto = hostURL.Scheme
c.addr = hostURL.Host
c.basePath = hostURL.Path
if transport, ok := c.client.Transport.(*http.Transport); ok {
return sockets.ConfigureTransport(transport, c.proto, c.addr)
}
return errors.Errorf("cannot apply host to transport: %T", c.client.Transport)
}
}
// WithHostFromEnv overrides the client host with the host specified in the
// DOCKER_HOST ([EnvOverrideHost]) environment variable. If DOCKER_HOST is not set,
// or set to an empty value, the host is not modified.
func WithHostFromEnv() Opt {
return func(c *Client) error {
if host := os.Getenv(EnvOverrideHost); host != "" {
return WithHost(host)(c)
}
return nil
}
}
// WithHTTPClient overrides the client's HTTP client with the specified one.
func WithHTTPClient(client *http.Client) Opt {
return func(c *Client) error {
if client != nil {
c.client = client
}
return nil
}
}
// WithTimeout configures the time limit for requests made by the HTTP client.
func WithTimeout(timeout time.Duration) Opt {
return func(c *Client) error {
c.client.Timeout = timeout
return nil
}
}
// WithUserAgent configures the User-Agent header to use for HTTP requests.
// It overrides any User-Agent set in headers. When set to an empty string,
// the User-Agent header is removed, and no header is sent.
func WithUserAgent(ua string) Opt {
return func(c *Client) error {
c.userAgent = &ua
return nil
}
}
// WithHTTPHeaders appends custom HTTP headers to the client's default headers.
// It does not allow for built-in headers (such as "User-Agent", if set) to
// be overridden. Also see [WithUserAgent].
func WithHTTPHeaders(headers map[string]string) Opt {
return func(c *Client) error {
c.customHTTPHeaders = headers
return nil
}
}
// WithScheme overrides the client scheme with the specified one.
func WithScheme(scheme string) Opt {
return func(c *Client) error {
c.scheme = scheme
return nil
}
}
// WithTLSClientConfig applies a TLS config to the client transport.
func WithTLSClientConfig(cacertPath, certPath, keyPath string) Opt {
return func(c *Client) error {
transport, ok := c.client.Transport.(*http.Transport)
if !ok {
return errors.Errorf("cannot apply tls config to transport: %T", c.client.Transport)
}
config, err := tlsconfig.Client(tlsconfig.Options{
CAFile: cacertPath,
CertFile: certPath,
KeyFile: keyPath,
ExclusiveRootPools: true,
})
if err != nil {
return errors.Wrap(err, "failed to create tls config")
}
transport.TLSClientConfig = config
return nil
}
}
// WithTLSClientConfigFromEnv configures the client's TLS settings with the
// settings in the DOCKER_CERT_PATH ([EnvOverrideCertPath]) and DOCKER_TLS_VERIFY
// ([EnvTLSVerify]) environment variables. If DOCKER_CERT_PATH is not set or empty,
// TLS configuration is not modified.
//
// WithTLSClientConfigFromEnv uses the following environment variables:
//
// - DOCKER_CERT_PATH ([EnvOverrideCertPath]) to specify the directory from
// which to load the TLS certificates ("ca.pem", "cert.pem", "key.pem").
// - DOCKER_TLS_VERIFY ([EnvTLSVerify]) to enable or disable TLS verification
// (off by default).
func WithTLSClientConfigFromEnv() Opt {
return func(c *Client) error {
dockerCertPath := os.Getenv(EnvOverrideCertPath)
if dockerCertPath == "" {
return nil
}
tlsc, err := tlsconfig.Client(tlsconfig.Options{
CAFile: filepath.Join(dockerCertPath, "ca.pem"),
CertFile: filepath.Join(dockerCertPath, "cert.pem"),
KeyFile: filepath.Join(dockerCertPath, "key.pem"),
InsecureSkipVerify: os.Getenv(EnvTLSVerify) == "",
})
if err != nil {
return err
}
c.client = &http.Client{
Transport: &http.Transport{TLSClientConfig: tlsc},
CheckRedirect: CheckRedirect,
}
return nil
}
}
// WithVersion overrides the client version with the specified one. If an empty
// version is provided, the value is ignored to allow version negotiation
// (see [WithAPIVersionNegotiation]).
func WithVersion(version string) Opt {
return func(c *Client) error {
if v := strings.TrimPrefix(version, "v"); v != "" {
c.version = v
c.manualOverride = true
}
return nil
}
}
// WithVersionFromEnv overrides the client version with the version specified in
// the DOCKER_API_VERSION ([EnvOverrideAPIVersion]) environment variable.
// If DOCKER_API_VERSION is not set, or set to an empty value, the version
// is not modified.
func WithVersionFromEnv() Opt {
return func(c *Client) error {
return WithVersion(os.Getenv(EnvOverrideAPIVersion))(c)
}
}
// WithAPIVersionNegotiation enables automatic API version negotiation for the client.
// With this option enabled, the client automatically negotiates the API version
// to use when making requests. API version negotiation is performed on the first
// request; subsequent requests do not re-negotiate.
func WithAPIVersionNegotiation() Opt {
return func(c *Client) error {
c.negotiateVersion = true
return nil
}
}
// WithTraceProvider sets the trace provider for the client.
// If this is not set then the global trace provider will be used.
func WithTraceProvider(provider trace.TracerProvider) Opt {
return WithTraceOptions(otelhttp.WithTracerProvider(provider))
}
// WithTraceOptions sets tracing span options for the client.
func WithTraceOptions(opts ...otelhttp.Option) Opt {
return func(c *Client) error {
c.traceOpts = append(c.traceOpts, opts...)
return nil
}
}

View File

@@ -1,81 +0,0 @@
package client
import (
"context"
"net/http"
"path"
"strings"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/build"
"github.com/docker/docker/api/types/swarm"
)
// Ping pings the server and returns the value of the "Docker-Experimental",
// "Builder-Version", "OS-Type" & "API-Version" headers. It attempts to use
// a HEAD request on the endpoint, but falls back to GET if HEAD is not supported
// by the daemon. It ignores internal server errors returned by the API, which
// may be returned if the daemon is in an unhealthy state, but returns errors
// for other non-success status codes, failing to connect to the API, or failing
// to parse the API response.
func (cli *Client) Ping(ctx context.Context) (types.Ping, error) {
var ping types.Ping
// Using cli.buildRequest() + cli.doRequest() instead of cli.sendRequest()
// because ping requests are used during API version negotiation, so we want
// to hit the non-versioned /_ping endpoint, not /v1.xx/_ping
req, err := cli.buildRequest(ctx, http.MethodHead, path.Join(cli.basePath, "/_ping"), nil, nil)
if err != nil {
return ping, err
}
resp, err := cli.doRequest(req)
if err != nil {
if IsErrConnectionFailed(err) {
return ping, err
}
// We managed to connect, but got some error; continue and try GET request.
} else {
defer ensureReaderClosed(resp)
switch resp.StatusCode {
case http.StatusOK, http.StatusInternalServerError:
// Server handled the request, so parse the response
return parsePingResponse(cli, resp)
}
}
// HEAD failed; fallback to GET.
req.Method = http.MethodGet
resp, err = cli.doRequest(req)
defer ensureReaderClosed(resp)
if err != nil {
return ping, err
}
return parsePingResponse(cli, resp)
}
func parsePingResponse(cli *Client, resp *http.Response) (types.Ping, error) {
if resp == nil {
return types.Ping{}, nil
}
var ping types.Ping
if resp.Header == nil {
return ping, cli.checkResponseErr(resp)
}
ping.APIVersion = resp.Header.Get("Api-Version")
ping.OSType = resp.Header.Get("Ostype")
if resp.Header.Get("Docker-Experimental") == "true" {
ping.Experimental = true
}
if bv := resp.Header.Get("Builder-Version"); bv != "" {
ping.BuilderVersion = build.BuilderVersion(bv)
}
if si := resp.Header.Get("Swarm"); si != "" {
state, role, _ := strings.Cut(si, "/")
ping.SwarmStatus = &swarm.Status{
NodeState: swarm.LocalNodeState(state),
ControlAvailable: role == "manager",
}
}
return ping, cli.checkResponseErr(resp)
}

View File

@@ -1,23 +0,0 @@
package client
import (
"context"
"io"
"net/http"
"net/url"
"github.com/docker/docker/api/types"
)
// PluginCreate creates a plugin
func (cli *Client) PluginCreate(ctx context.Context, createContext io.Reader, createOptions types.PluginCreateOptions) error {
headers := http.Header(make(map[string][]string))
headers.Set("Content-Type", "application/x-tar")
query := url.Values{}
query.Set("name", createOptions.RepoName)
resp, err := cli.postRaw(ctx, "/plugins/create", query, createContext, headers)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,23 +0,0 @@
package client
import (
"context"
"net/url"
"github.com/docker/docker/api/types"
)
// PluginDisable disables a plugin
func (cli *Client) PluginDisable(ctx context.Context, name string, options types.PluginDisableOptions) error {
name, err := trimID("plugin", name)
if err != nil {
return err
}
query := url.Values{}
if options.Force {
query.Set("force", "1")
}
resp, err := cli.post(ctx, "/plugins/"+name+"/disable", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,23 +0,0 @@
package client
import (
"context"
"net/url"
"strconv"
"github.com/docker/docker/api/types"
)
// PluginEnable enables a plugin
func (cli *Client) PluginEnable(ctx context.Context, name string, options types.PluginEnableOptions) error {
name, err := trimID("plugin", name)
if err != nil {
return err
}
query := url.Values{}
query.Set("timeout", strconv.Itoa(options.Timeout))
resp, err := cli.post(ctx, "/plugins/"+name+"/enable", query, nil, nil)
ensureReaderClosed(resp)
return err
}

View File

@@ -1,32 +0,0 @@
package client
import (
"bytes"
"context"
"encoding/json"
"io"
"github.com/docker/docker/api/types"
)
// PluginInspectWithRaw inspects an existing plugin
func (cli *Client) PluginInspectWithRaw(ctx context.Context, name string) (*types.Plugin, []byte, error) {
name, err := trimID("plugin", name)
if err != nil {
return nil, nil, err
}
resp, err := cli.get(ctx, "/plugins/"+name+"/json", nil, nil)
defer ensureReaderClosed(resp)
if err != nil {
return nil, nil, err
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, nil, err
}
var p types.Plugin
rdr := bytes.NewReader(body)
err = json.NewDecoder(rdr).Decode(&p)
return &p, body, err
}

View File

@@ -1,117 +0,0 @@
package client
import (
"context"
"encoding/json"
"io"
"net/http"
"net/url"
cerrdefs "github.com/containerd/errdefs"
"github.com/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/pkg/errors"
)
// PluginInstall installs a plugin
func (cli *Client) PluginInstall(ctx context.Context, name string, options types.PluginInstallOptions) (_ io.ReadCloser, retErr error) {
query := url.Values{}
if _, err := reference.ParseNormalizedNamed(options.RemoteRef); err != nil {
return nil, errors.Wrap(err, "invalid remote reference")
}
query.Set("remote", options.RemoteRef)
privileges, err := cli.checkPluginPermissions(ctx, query, options)
if err != nil {
return nil, err
}
// set name for plugin pull, if empty should default to remote reference
query.Set("name", name)
resp, err := cli.tryPluginPull(ctx, query, privileges, options.RegistryAuth)
if err != nil {
return nil, err
}
name = resp.Header.Get("Docker-Plugin-Name")
pr, pw := io.Pipe()
go func() { // todo: the client should probably be designed more around the actual api
_, err := io.Copy(pw, resp.Body)
if err != nil {
_ = pw.CloseWithError(err)
return
}
defer func() {
if retErr != nil {
delResp, _ := cli.delete(ctx, "/plugins/"+name, nil, nil)
ensureReaderClosed(delResp)
}
}()
if len(options.Args) > 0 {
if err := cli.PluginSet(ctx, name, options.Args); err != nil {
_ = pw.CloseWithError(err)
return
}
}
if options.Disabled {
_ = pw.Close()
return
}
enableErr := cli.PluginEnable(ctx, name, types.PluginEnableOptions{Timeout: 0})
_ = pw.CloseWithError(enableErr)
}()
return pr, nil
}
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (*http.Response, error) {
return cli.get(ctx, "/plugins/privileges", query, http.Header{
registry.AuthHeader: {registryAuth},
})
}
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (*http.Response, error) {
return cli.post(ctx, "/plugins/pull", query, privileges, http.Header{
registry.AuthHeader: {registryAuth},
})
}
func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values, options types.PluginInstallOptions) (types.PluginPrivileges, error) {
resp, err := cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
if cerrdefs.IsUnauthorized(err) && options.PrivilegeFunc != nil {
// todo: do inspect before to check existing name before checking privileges
newAuthHeader, privilegeErr := options.PrivilegeFunc(ctx)
if privilegeErr != nil {
ensureReaderClosed(resp)
return nil, privilegeErr
}
options.RegistryAuth = newAuthHeader
resp, err = cli.tryPluginPrivileges(ctx, query, options.RegistryAuth)
}
if err != nil {
ensureReaderClosed(resp)
return nil, err
}
var privileges types.PluginPrivileges
if err := json.NewDecoder(resp.Body).Decode(&privileges); err != nil {
ensureReaderClosed(resp)
return nil, err
}
ensureReaderClosed(resp)
if !options.AcceptAllPermissions && options.AcceptPermissionsFunc != nil && len(privileges) > 0 {
accept, err := options.AcceptPermissionsFunc(ctx, privileges)
if err != nil {
return nil, err
}
if !accept {
return nil, errors.Errorf("permission denied while installing plugin %s", options.RemoteRef)
}
}
return privileges, nil
}

View File

@@ -1,33 +0,0 @@
package client
import (
"context"
"encoding/json"
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
)
// PluginList returns the installed plugins
func (cli *Client) PluginList(ctx context.Context, filter filters.Args) (types.PluginsListResponse, error) {
var plugins types.PluginsListResponse
query := url.Values{}
if filter.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, filter)
if err != nil {
return plugins, err
}
query.Set("filters", filterJSON)
}
resp, err := cli.get(ctx, "/plugins", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return plugins, err
}
err = json.NewDecoder(resp.Body).Decode(&plugins)
return plugins, err
}

Some files were not shown because too many files have changed in this diff Show More