Alpine base image and some dependencies upgraded

Details in the reweave CHANGELOG
This commit is contained in:
Raj Chaudhuri committed 2023-11-12 23:45:30 +05:30
1 parent 1ceeca80e6
commit 0d58e17954
368 files changed
+23406 -9163

No files matched your search

+9 -9
View File
@@ -10,10 +10,10 @@ require (
github.com/containernetworking/cni v1.1.2
github.com/containernetworking/plugins v1.2.0
github.com/coreos/go-iptables v0.6.0
github.com/docker/docker v23.0.3+incompatible
github.com/docker/docker v24.0.7+incompatible
github.com/docker/libnetwork v0.8.0-dev.2.0.20180212220201-119badbd737b
github.com/docker/machine v0.14.0
github.com/fsouza/go-dockerclient v1.2.0
github.com/fsouza/go-dockerclient v1.10.0
github.com/google/gopacket v1.1.16
github.com/gorilla/mux v1.8.0
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56
@@ -30,8 +30,8 @@ require (
github.com/weaveworks/go-checkpoint v0.0.0-20170503165305-ebbb8b0518ab
github.com/weaveworks/go-odp v0.0.0-20181017121109-6b0aa22550d9
github.com/weaveworks/mesh v0.0.0-20191105120815-58dbcc3e8e63
golang.org/x/crypto v0.1.0
golang.org/x/sys v0.6.0
golang.org/x/crypto v0.14.0
golang.org/x/sys v0.13.0
golang.org/x/tools v0.7.0
k8s.io/api v0.26.2
k8s.io/apimachinery v0.26.2
@@ -44,7 +44,7 @@ require github.com/mattn/go-isatty v0.0.18 // indirect
require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/containerd/containerd v1.7.0 // indirect
@@ -74,7 +74,7 @@ require (
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mdlayher/raw v0.0.0-20181016155347-fa5ef3332ca9 // indirect
github.com/moby/patternmatcher v0.5.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -92,10 +92,10 @@ require (
github.com/safchain/ethtool v0.2.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/oauth2 v0.4.0 // indirect
golang.org/x/term v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.30.0 // indirect
+20 -18
View File
@@ -31,12 +31,13 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
github.com/Microsoft/hcsshim v0.10.0-rc.7 h1:HBytQPxcv8Oy4244zbQbe6hnOnx544eL5QPUqhJldz8=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -70,7 +71,6 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/containerd v1.7.0 h1:G/ZQr3gMZs6ZT0qPUZ15znx5QSdQdASW11nXTLTM2Pg=
github.com/containerd/containerd v1.7.0/go.mod h1:QfR7Efgb/6X2BDpTPJRvPTYDE9rsF0FsXX9J8sIs/sc=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containernetworking/cni v1.1.2 h1:wtRGZVv7olUHMOqouPpn3cXJWpJgM6+EUl31EQbXALQ=
github.com/containernetworking/cni v1.1.2/go.mod h1:sDpYKmGVENF3s6uvMvGgldDWeG8dMxakj/u+i9ht9vw=
github.com/containernetworking/plugins v1.2.0 h1:SWgg3dQG1yzUo4d9iD8cwSVh1VqI+bP7mkPDoSfP9VU=
@@ -82,14 +82,15 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.8.2-beta.1+incompatible h1:gILO60VLD2v28ozemv4aAwDb8ds5U2O/vD/sBXbd7Rw=
github.com/docker/distribution v2.8.2-beta.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v23.0.3+incompatible h1:9GhVsShNWz1hO//9BNg/dpMnZW25KydO4wtVxWAIbho=
github.com/docker/docker v23.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/docker v24.0.7+incompatible h1:Wo6l37AuwP3JaMnZa226lzVXGA3F9Ig1seQen0cKYlM=
github.com/docker/docker v24.0.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
@@ -112,8 +113,8 @@ github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsouza/go-dockerclient v1.2.0 h1:lmjnUbZFR+De5PfuXCk62hAIlkokNtD9CaGPR8Iu5UU=
github.com/fsouza/go-dockerclient v1.2.0/go.mod h1:KpcjM623fQYE9MZiTGzKhjfxXAV9wbyX2C1cyRHfhl0=
github.com/fsouza/go-dockerclient v1.10.0 h1:ppSBsbR60I1DFbV4Ag7LlHlHakHFRNLk9XakATW1yVQ=
github.com/fsouza/go-dockerclient v1.10.0/go.mod h1:+iNzAW78AzClIBTZ6WFjkaMvOgz68GyCJ236b1opLTs=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -266,8 +267,8 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1f
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c=
github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
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/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=
@@ -411,8 +412,8 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -481,8 +482,8 @@ golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -558,12 +559,13 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -571,8 +573,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+10
View File
@@ -6,6 +6,16 @@ All changes made to the weave net codebase during the reweave effort will be doc
### Changed
* Alpine base image upgraded to alpine:2.18.4, and `apk upgrade` applied
* Upgraded golang.org/x/net to v0.17.0. This upgraded some dependecies
* Upgraded github.com/docker/docker to v24.0.7. This caused a compilation error
* Upgraded github.com/fsouza/go-dockerclient to v1.10.0. This resolved the error
## 2.8.2-beta10 (126f3ab9)
### Changed
* Alpine base image upgraded to alpine:2.18.3
* Updated documentation
* Changed [reweave/tool/build-images.sh](reweave/tool/build-images.sh) to be consistent with documentation
+2 -2
View File
@@ -1,7 +1,7 @@
IMAGE_VERSION ?= 2.8.2-beta10
IMAGE_VERSION ?= 2.8.2-beta11
REGISTRY_USER ?= weaveworks
ALPINE_BASEIMAGE ?= alpine:3.18.3
ALPINE_BASEIMAGE ?= alpine:3.18.4
# Targets
.PHONY: build-images
+4
View File
@@ -79,6 +79,10 @@ EOMAKE
# required in the alpine base image.
FROM --platform=linux/${TARGETARCH} ${ALPINE_BASEIMAGE} as alpinebase
# Any additional tweaks will appear here
# Last update on top of alpine:3.18.4
RUN apk update \
&& apk upgrade \
&& rm -rf /var/cache/apk/*
# End Stage 3
########
+1 -1
View File
@@ -1 +1 @@
Image version: 2.8.2-beta10
Image version: 2.8.2-beta11
+1 -1
View File
@@ -1 +1 @@
weave-kube CVE Count: 18
weave-kube CVE Count: 0
+1 -20
View File
@@ -1,20 +1 @@
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
bind-libs 9.18.16-r0 9.18.19-r0 apk CVE-2023-4236 High
bind-libs 9.18.16-r0 9.18.19-r0 apk CVE-2023-3341 High
bind-tools 9.18.16-r0 9.18.19-r0 apk CVE-2023-4236 High
bind-tools 9.18.16-r0 9.18.19-r0 apk CVE-2023-3341 High
curl 8.2.1-r0 8.4.0-r0 apk CVE-2023-38545 Critical
curl 8.2.1-r0 8.3.0-r0 apk CVE-2023-38039 High
curl 8.2.1-r0 8.4.0-r0 apk CVE-2023-38546 Low
github.com/docker/docker v23.0.3+incompatible 24.0.7 go-module GHSA-jq35-85cj-fj4p Medium
golang.org/x/net v0.8.0 0.17.0 go-module GHSA-4374-p667-p6c8 High
golang.org/x/net v0.8.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium
golang.org/x/net v0.8.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium
libcrypto3 3.1.2-r0 3.1.4-r0 apk CVE-2023-5363 High
libcrypto3 3.1.2-r0 3.1.4-r1 apk CVE-2023-5678 Unknown
libcurl 8.2.1-r0 8.4.0-r0 apk CVE-2023-38545 Critical
libcurl 8.2.1-r0 8.3.0-r0 apk CVE-2023-38039 High
libcurl 8.2.1-r0 8.4.0-r0 apk CVE-2023-38546 Low
libssl3 3.1.2-r0 3.1.4-r0 apk CVE-2023-5363 High
libssl3 3.1.2-r0 3.1.4-r1 apk CVE-2023-5678 Unknown
nghttp2-libs 1.55.1-r0 1.57.0-r0 apk CVE-2023-44487 High
No vulnerabilities found
+1 -1
View File
@@ -1 +1 @@
weave-npc CVE Count: 6
weave-npc CVE Count: 0
+1 -8
View File
@@ -1,8 +1 @@
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
golang.org/x/net v0.8.0 0.17.0 go-module GHSA-4374-p667-p6c8 High
golang.org/x/net v0.8.0 0.17.0 go-module GHSA-qppj-fm5r-hxr3 Medium
golang.org/x/net v0.8.0 0.13.0 go-module GHSA-2wrh-6pvc-2jm9 Medium
libcrypto3 3.1.2-r0 3.1.4-r0 apk CVE-2023-5363 High
libcrypto3 3.1.2-r0 3.1.4-r1 apk CVE-2023-5678 Unknown
libssl3 3.1.2-r0 3.1.4-r0 apk CVE-2023-5363 High
libssl3 3.1.2-r0 3.1.4-r1 apk CVE-2023-5678 Unknown
No vulnerabilities found
+16 -11
View File
@@ -8,12 +8,8 @@ linters:
- containedctx # struct contains a context
- dupl # duplicate code
- errname # erorrs are named correctly
- goconst # strings that should be constants
- godot # comments end in a period
- misspell
- nolintlint # "//nolint" directives are properly explained
- revive # golint replacement
- stylecheck # golint replacement, less configurable than revive
- unconvert # unnecessary conversions
- wastedassign
@@ -23,10 +19,7 @@ linters:
- exhaustive # check exhaustiveness of enum switch statements
- gofmt # files are gofmt'ed
- gosec # security
- nestif # deeply nested ifs
- nilerr # returns nil even with non-nil error
- prealloc # slices that can be pre-allocated
- structcheck # unused struct fields
- unparam # unused function params
issues:
@@ -42,6 +35,18 @@ issues:
text: "^line-length-limit: "
source: "^//(go:generate|sys) "
#TODO: remove after upgrading to go1.18
# ignore comment spacing for nolint and sys directives
- linters:
- revive
text: "^comment-spacings: no space between comment delimiter and comment text"
source: "//(cspell:|nolint:|sys |todo)"
# not on go 1.18 yet, so no any
- linters:
- revive
text: "^use-any: since GO 1.18 'interface{}' can be replaced by 'any'"
# allow unjustified ignores of error checks in defer statements
- linters:
- nolintlint
@@ -56,6 +61,8 @@ issues:
linters-settings:
exhaustive:
default-signifies-exhaustive: true
govet:
enable-all: true
disable:
@@ -98,6 +105,8 @@ linters-settings:
disabled: true
- name: flag-parameter # excessive, and a common idiom we use
disabled: true
- name: unhandled-error # warns over common fmt.Print* and io.Close; rely on errcheck instead
disabled: true
# general config
- name: line-length-limit
arguments:
@@ -138,7 +147,3 @@ linters-settings:
- VPCI
- WCOW
- WIM
stylecheck:
checks:
- "all"
- "-ST1003" # use revive's var naming
+3 -3
View File
@@ -23,7 +23,7 @@ import (
const afHVSock = 34 // AF_HYPERV
// Well known Service and VM IDs
//https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
// https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/make-integration-service#vmid-wildcards
// HvsockGUIDWildcard is the wildcard VmId for accepting connections from all partitions.
func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
@@ -31,7 +31,7 @@ func HvsockGUIDWildcard() guid.GUID { // 00000000-0000-0000-0000-000000000000
}
// HvsockGUIDBroadcast is the wildcard VmId for broadcasting sends to all partitions.
func HvsockGUIDBroadcast() guid.GUID { //ffffffff-ffff-ffff-ffff-ffffffffffff
func HvsockGUIDBroadcast() guid.GUID { // ffffffff-ffff-ffff-ffff-ffffffffffff
return guid.GUID{
Data1: 0xffffffff,
Data2: 0xffff,
@@ -246,7 +246,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
var addrbuf [addrlen * 2]byte
var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /*rxdatalen*/, addrlen, addrlen, &bytes, &c.o)
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0 /* rxdatalen */, addrlen, addrlen, &bytes, &c.o)
if _, err = l.sock.asyncIO(c, nil, bytes, err); err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
}
+2
View File
@@ -0,0 +1,2 @@
// This package contains Win32 filesystem functionality.
package fs
+202
View File
@@ -0,0 +1,202 @@
//go:build windows
package fs
import (
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/stringbuffer"
)
//go:generate go run github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go fs.go
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew
//sys CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) [failretval==windows.InvalidHandle] = CreateFileW
const NullHandle windows.Handle = 0
// AccessMask defines standard, specific, and generic rights.
//
// Bitmask:
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---------------+---------------+-------------------------------+
// |G|G|G|G|Resvd|A| StandardRights| SpecificRights |
// |R|W|E|A| |S| | |
// +-+-------------+---------------+-------------------------------+
//
// GR Generic Read
// GW Generic Write
// GE Generic Exectue
// GA Generic All
// Resvd Reserved
// AS Access Security System
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/access-mask
//
// https://learn.microsoft.com/en-us/windows/win32/secauthz/generic-access-rights
//
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-access-rights-constants
type AccessMask = windows.ACCESS_MASK
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// Not actually any.
//
// For CreateFile: "query certain metadata such as file, directory, or device attributes without accessing that file or device"
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#parameters
FILE_ANY_ACCESS AccessMask = 0
// Specific Object Access
// from ntioapi.h
FILE_READ_DATA AccessMask = (0x0001) // file & pipe
FILE_LIST_DIRECTORY AccessMask = (0x0001) // directory
FILE_WRITE_DATA AccessMask = (0x0002) // file & pipe
FILE_ADD_FILE AccessMask = (0x0002) // directory
FILE_APPEND_DATA AccessMask = (0x0004) // file
FILE_ADD_SUBDIRECTORY AccessMask = (0x0004) // directory
FILE_CREATE_PIPE_INSTANCE AccessMask = (0x0004) // named pipe
FILE_READ_EA AccessMask = (0x0008) // file & directory
FILE_READ_PROPERTIES AccessMask = FILE_READ_EA
FILE_WRITE_EA AccessMask = (0x0010) // file & directory
FILE_WRITE_PROPERTIES AccessMask = FILE_WRITE_EA
FILE_EXECUTE AccessMask = (0x0020) // file
FILE_TRAVERSE AccessMask = (0x0020) // directory
FILE_DELETE_CHILD AccessMask = (0x0040) // directory
FILE_READ_ATTRIBUTES AccessMask = (0x0080) // all
FILE_WRITE_ATTRIBUTES AccessMask = (0x0100) // all
FILE_ALL_ACCESS AccessMask = (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
FILE_GENERIC_READ AccessMask = (STANDARD_RIGHTS_READ | FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE)
FILE_GENERIC_WRITE AccessMask = (STANDARD_RIGHTS_WRITE | FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE)
FILE_GENERIC_EXECUTE AccessMask = (STANDARD_RIGHTS_EXECUTE | FILE_READ_ATTRIBUTES | FILE_EXECUTE | SYNCHRONIZE)
SPECIFIC_RIGHTS_ALL AccessMask = 0x0000FFFF
// Standard Access
// from ntseapi.h
DELETE AccessMask = 0x0001_0000
READ_CONTROL AccessMask = 0x0002_0000
WRITE_DAC AccessMask = 0x0004_0000
WRITE_OWNER AccessMask = 0x0008_0000
SYNCHRONIZE AccessMask = 0x0010_0000
STANDARD_RIGHTS_REQUIRED AccessMask = 0x000F_0000
STANDARD_RIGHTS_READ AccessMask = READ_CONTROL
STANDARD_RIGHTS_WRITE AccessMask = READ_CONTROL
STANDARD_RIGHTS_EXECUTE AccessMask = READ_CONTROL
STANDARD_RIGHTS_ALL AccessMask = 0x001F_0000
)
type FileShareMode uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
FILE_SHARE_NONE FileShareMode = 0x00
FILE_SHARE_READ FileShareMode = 0x01
FILE_SHARE_WRITE FileShareMode = 0x02
FILE_SHARE_DELETE FileShareMode = 0x04
FILE_SHARE_VALID_FLAGS FileShareMode = 0x07
)
type FileCreationDisposition uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
// from winbase.h
CREATE_NEW FileCreationDisposition = 0x01
CREATE_ALWAYS FileCreationDisposition = 0x02
OPEN_EXISTING FileCreationDisposition = 0x03
OPEN_ALWAYS FileCreationDisposition = 0x04
TRUNCATE_EXISTING FileCreationDisposition = 0x05
)
// CreateFile and co. take flags or attributes together as one parameter.
// Define alias until we can use generics to allow both
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
type FileFlagOrAttribute uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winnt.h
FILE_FLAG_WRITE_THROUGH FileFlagOrAttribute = 0x8000_0000
FILE_FLAG_OVERLAPPED FileFlagOrAttribute = 0x4000_0000
FILE_FLAG_NO_BUFFERING FileFlagOrAttribute = 0x2000_0000
FILE_FLAG_RANDOM_ACCESS FileFlagOrAttribute = 0x1000_0000
FILE_FLAG_SEQUENTIAL_SCAN FileFlagOrAttribute = 0x0800_0000
FILE_FLAG_DELETE_ON_CLOSE FileFlagOrAttribute = 0x0400_0000
FILE_FLAG_BACKUP_SEMANTICS FileFlagOrAttribute = 0x0200_0000
FILE_FLAG_POSIX_SEMANTICS FileFlagOrAttribute = 0x0100_0000
FILE_FLAG_OPEN_REPARSE_POINT FileFlagOrAttribute = 0x0020_0000
FILE_FLAG_OPEN_NO_RECALL FileFlagOrAttribute = 0x0010_0000
FILE_FLAG_FIRST_PIPE_INSTANCE FileFlagOrAttribute = 0x0008_0000
)
type FileSQSFlag = FileFlagOrAttribute
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const ( // from winbase.h
SECURITY_ANONYMOUS FileSQSFlag = FileSQSFlag(SecurityAnonymous << 16)
SECURITY_IDENTIFICATION FileSQSFlag = FileSQSFlag(SecurityIdentification << 16)
SECURITY_IMPERSONATION FileSQSFlag = FileSQSFlag(SecurityImpersonation << 16)
SECURITY_DELEGATION FileSQSFlag = FileSQSFlag(SecurityDelegation << 16)
SECURITY_SQOS_PRESENT FileSQSFlag = 0x00100000
SECURITY_VALID_SQOS_FLAGS FileSQSFlag = 0x001F0000
)
// GetFinalPathNameByHandle flags
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew#parameters
type GetFinalPathFlag uint32
//nolint:revive // SNAKE_CASE is not idiomatic in Go, but aligned with Win32 API.
const (
GetFinalPathDefaultFlag GetFinalPathFlag = 0x0
FILE_NAME_NORMALIZED GetFinalPathFlag = 0x0
FILE_NAME_OPENED GetFinalPathFlag = 0x8
VOLUME_NAME_DOS GetFinalPathFlag = 0x0
VOLUME_NAME_GUID GetFinalPathFlag = 0x1
VOLUME_NAME_NT GetFinalPathFlag = 0x2
VOLUME_NAME_NONE GetFinalPathFlag = 0x4
)
// getFinalPathNameByHandle facilitates calling the Windows API GetFinalPathNameByHandle
// with the given handle and flags. It transparently takes care of creating a buffer of the
// correct size for the call.
//
// https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
func GetFinalPathNameByHandle(h windows.Handle, flags GetFinalPathFlag) (string, error) {
b := stringbuffer.NewWString()
//TODO: can loop infinitely if Win32 keeps returning the same (or a larger) n?
for {
n, err := windows.GetFinalPathNameByHandle(h, b.Pointer(), b.Cap(), uint32(flags))
if err != nil {
return "", err
}
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).
// Resize and try again.
if n > b.Cap() {
b.ResizeTo(n)
continue
}
// If the buffer is large enough, n will be the size not including the null terminator.
// Convert to a Go string and return.
return b.String(), nil
}
}
+12
View File
@@ -0,0 +1,12 @@
package fs
// https://learn.microsoft.com/en-us/windows/win32/api/winnt/ne-winnt-security_impersonation_level
type SecurityImpersonationLevel int32 // C default enums underlying type is `int`, which is Go `int32`
// Impersonation levels
const (
SecurityAnonymous SecurityImpersonationLevel = 0
SecurityIdentification SecurityImpersonationLevel = 1
SecurityImpersonation SecurityImpersonationLevel = 2
SecurityDelegation SecurityImpersonationLevel = 3
)
+64
View File
@@ -0,0 +1,64 @@
//go:build windows
// Code generated by 'go generate' using "github.com/Microsoft/go-winio/tools/mkwinsyscall"; DO NOT EDIT.
package fs
import (
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
var _ unsafe.Pointer
// Do the interface allocations only once for common
// Errno values.
const (
errnoERROR_IO_PENDING = 997
)
var (
errERROR_IO_PENDING error = syscall.Errno(errnoERROR_IO_PENDING)
errERROR_EINVAL error = syscall.EINVAL
)
// errnoErr returns common boxed Errno values, to prevent
// allocations at runtime.
func errnoErr(e syscall.Errno) error {
switch e {
case 0:
return errERROR_EINVAL
case errnoERROR_IO_PENDING:
return errERROR_IO_PENDING
}
// TODO: add more here, after collecting data on the common
// error values see on Windows. (perhaps when running
// all.bat?)
return e
}
var (
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
procCreateFileW = modkernel32.NewProc("CreateFileW")
)
func CreateFile(name string, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _CreateFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _CreateFile(name *uint16, access AccessMask, mode FileShareMode, sa *syscall.SecurityAttributes, createmode FileCreationDisposition, attrs FileFlagOrAttribute, templatefile windows.Handle) (handle windows.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = windows.Handle(r0)
if handle == windows.InvalidHandle {
err = errnoErr(e1)
}
return
}
+2 -2
View File
@@ -100,8 +100,8 @@ func (f *runtimeFunc) Load() error {
(*byte)(unsafe.Pointer(&f.addr)),
uint32(unsafe.Sizeof(f.addr)),
&n,
nil, //overlapped
0, //completionRoutine
nil, // overlapped
0, // completionRoutine
)
})
return f.err
+132
View File
@@ -0,0 +1,132 @@
package stringbuffer
import (
"sync"
"unicode/utf16"
)
// TODO: worth exporting and using in mkwinsyscall?
// Uint16BufferSize is the buffer size in the pool, chosen somewhat arbitrarily to accommodate
// large path strings:
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
const MinWStringCap = 310
// use *[]uint16 since []uint16 creates an extra allocation where the slice header
// is copied to heap and then referenced via pointer in the interface header that sync.Pool
// stores.
var pathPool = sync.Pool{ // if go1.18+ adds Pool[T], use that to store []uint16 directly
New: func() interface{} {
b := make([]uint16, MinWStringCap)
return &b
},
}
func newBuffer() []uint16 { return *(pathPool.Get().(*[]uint16)) }
// freeBuffer copies the slice header data, and puts a pointer to that in the pool.
// This avoids taking a pointer to the slice header in WString, which can be set to nil.
func freeBuffer(b []uint16) { pathPool.Put(&b) }
// WString is a wide string buffer ([]uint16) meant for storing UTF-16 encoded strings
// for interacting with Win32 APIs.
// Sizes are specified as uint32 and not int.
//
// It is not thread safe.
type WString struct {
// type-def allows casting to []uint16 directly, use struct to prevent that and allow adding fields in the future.
// raw buffer
b []uint16
}
// NewWString returns a [WString] allocated from a shared pool with an
// initial capacity of at least [MinWStringCap].
// Since the buffer may have been previously used, its contents are not guaranteed to be empty.
//
// The buffer should be freed via [WString.Free]
func NewWString() *WString {
return &WString{
b: newBuffer(),
}
}
func (b *WString) Free() {
if b.empty() {
return
}
freeBuffer(b.b)
b.b = nil
}
// ResizeTo grows the buffer to at least c and returns the new capacity, freeing the
// previous buffer back into pool.
func (b *WString) ResizeTo(c uint32) uint32 {
// allready sufficient (or n is 0)
if c <= b.Cap() {
return b.Cap()
}
if c <= MinWStringCap {
c = MinWStringCap
}
// allocate at-least double buffer size, as is done in [bytes.Buffer] and other places
if c <= 2*b.Cap() {
c = 2 * b.Cap()
}
b2 := make([]uint16, c)
if !b.empty() {
copy(b2, b.b)
freeBuffer(b.b)
}
b.b = b2
return c
}
// Buffer returns the underlying []uint16 buffer.
func (b *WString) Buffer() []uint16 {
if b.empty() {
return nil
}
return b.b
}
// Pointer returns a pointer to the first uint16 in the buffer.
// If the [WString.Free] has already been called, the pointer will be nil.
func (b *WString) Pointer() *uint16 {
if b.empty() {
return nil
}
return &b.b[0]
}
// String returns the returns the UTF-8 encoding of the UTF-16 string in the buffer.
//
// It assumes that the data is null-terminated.
func (b *WString) String() string {
// Using [windows.UTF16ToString] would require importing "golang.org/x/sys/windows"
// and would make this code Windows-only, which makes no sense.
// So copy UTF16ToString code into here.
// If other windows-specific code is added, switch to [windows.UTF16ToString]
s := b.b
for i, v := range s {
if v == 0 {
s = s[:i]
break
}
}
return string(utf16.Decode(s))
}
// Cap returns the underlying buffer capacity.
func (b *WString) Cap() uint32 {
if b.empty() {
return 0
}
return b.cap()
}
func (b *WString) cap() uint32 { return uint32(cap(b.b)) }
func (b *WString) empty() bool { return b == nil || b.cap() == 0 }
+13 -9
View File
@@ -16,11 +16,12 @@ import (
"unsafe"
"golang.org/x/sys/windows"
"github.com/Microsoft/go-winio/internal/fs"
)
//sys connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) = ConnectNamedPipe
//sys createNamedPipe(name string, flags uint32, pipeMode uint32, maxInstances uint32, outSize uint32, inSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateNamedPipeW
//sys createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) [failretval==syscall.InvalidHandle] = CreateFileW
//sys getNamedPipeInfo(pipe syscall.Handle, flags *uint32, outSize *uint32, inSize *uint32, maxInstances *uint32) (err error) = GetNamedPipeInfo
//sys getNamedPipeHandleState(pipe syscall.Handle, state *uint32, curInstances *uint32, maxCollectionCount *uint32, collectDataTimeout *uint32, userName *uint16, maxUserNameSize uint32) (err error) = GetNamedPipeHandleStateW
//sys localAlloc(uFlags uint32, length uint32) (ptr uintptr) = LocalAlloc
@@ -163,19 +164,21 @@ func (s pipeAddress) String() string {
}
// tryDialPipe attempts to dial the pipe at `path` until `ctx` cancellation or timeout.
func tryDialPipe(ctx context.Context, path *string, access uint32) (syscall.Handle, error) {
func tryDialPipe(ctx context.Context, path *string, access fs.AccessMask) (syscall.Handle, error) {
for {
select {
case <-ctx.Done():
return syscall.Handle(0), ctx.Err()
default:
h, err := createFile(*path,
wh, err := fs.CreateFile(*path,
access,
0,
nil,
syscall.OPEN_EXISTING,
windows.FILE_FLAG_OVERLAPPED|windows.SECURITY_SQOS_PRESENT|windows.SECURITY_ANONYMOUS,
0)
0, // mode
nil, // security attributes
fs.OPEN_EXISTING,
fs.FILE_FLAG_OVERLAPPED|fs.SECURITY_SQOS_PRESENT|fs.SECURITY_ANONYMOUS,
0, // template file handle
)
h := syscall.Handle(wh)
if err == nil {
return h, nil
}
@@ -219,7 +222,7 @@ func DialPipeContext(ctx context.Context, path string) (net.Conn, error) {
func DialPipeAccess(ctx context.Context, path string, access uint32) (net.Conn, error) {
var err error
var h syscall.Handle
h, err = tryDialPipe(ctx, &path, access)
h, err = tryDialPipe(ctx, &path, fs.AccessMask(access))
if err != nil {
return nil, err
}
@@ -279,6 +282,7 @@ func makeServerPipeHandle(path string, sd []byte, c *PipeConfig, first bool) (sy
}
defer localFree(ntPath.Buffer)
oa.ObjectName = &ntPath
oa.Attributes = windows.OBJ_CASE_INSENSITIVE
// The security descriptor is only needed for the first pipe.
if first {
-19
View File
@@ -63,7 +63,6 @@ var (
procBackupWrite = modkernel32.NewProc("BackupWrite")
procCancelIoEx = modkernel32.NewProc("CancelIoEx")
procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe")
procCreateFileW = modkernel32.NewProc("CreateFileW")
procCreateIoCompletionPort = modkernel32.NewProc("CreateIoCompletionPort")
procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW")
procGetCurrentThread = modkernel32.NewProc("GetCurrentThread")
@@ -305,24 +304,6 @@ func connectNamedPipe(pipe syscall.Handle, o *syscall.Overlapped) (err error) {
return
}
func createFile(name string, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
var _p0 *uint16
_p0, err = syscall.UTF16PtrFromString(name)
if err != nil {
return
}
return _createFile(_p0, access, mode, sa, createmode, attrs, templatefile)
}
func _createFile(name *uint16, access uint32, mode uint32, sa *syscall.SecurityAttributes, createmode uint32, attrs uint32, templatefile syscall.Handle) (handle syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall9(procCreateFileW.Addr(), 7, uintptr(unsafe.Pointer(name)), uintptr(access), uintptr(mode), uintptr(unsafe.Pointer(sa)), uintptr(createmode), uintptr(attrs), uintptr(templatefile), 0, 0)
handle = syscall.Handle(r0)
if handle == syscall.InvalidHandle {
err = errnoErr(e1)
}
return
}
func createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) {
r0, _, e1 := syscall.Syscall6(procCreateIoCompletionPort.Addr(), 4, uintptr(file), uintptr(port), uintptr(key), uintptr(threadCount), 0, 0)
newport = syscall.Handle(r0)
+18
View File
@@ -29,6 +29,7 @@ Adam Pointer <adam.pointer@skybettingandgaming.com>
Adam Singer <financeCoding@gmail.com>
Adam Walz <adam@adamwalz.net>
Adam Williams <awilliams@mirantis.com>
AdamKorcz <adam@adalogics.com>
Addam Hardy <addam.hardy@gmail.com>
Aditi Rajagopal <arajagopal@us.ibm.com>
Aditya <aditya@netroy.in>
@@ -81,6 +82,7 @@ Alex Goodman <wagoodman@gmail.com>
Alex Nordlund <alexander.nordlund@nasdaq.com>
Alex Olshansky <i@creagenics.com>
Alex Samorukov <samm@os2.kiev.ua>
Alex Stockinger <alex@atomicjar.com>
Alex Warhawk <ax.warhawk@gmail.com>
Alexander Artemenko <svetlyak.40wt@gmail.com>
Alexander Boyd <alex@opengroove.org>
@@ -198,6 +200,7 @@ Anusha Ragunathan <anusha.ragunathan@docker.com>
Anyu Wang <wanganyu@outlook.com>
apocas <petermdias@gmail.com>
Arash Deshmeh <adeshmeh@ca.ibm.com>
arcosx <arcosx@outlook.com>
ArikaChen <eaglesora@gmail.com>
Arko Dasgupta <arko@tetrate.io>
Arnaud Lefebvre <a.lefebvre@outlook.fr>
@@ -241,6 +244,7 @@ Benjamin Atkin <ben@benatkin.com>
Benjamin Baker <Benjamin.baker@utexas.edu>
Benjamin Boudreau <boudreau.benjamin@gmail.com>
Benjamin Böhmke <benjamin@boehmke.net>
Benjamin Wang <wachao@vmware.com>
Benjamin Yolken <yolken@stripe.com>
Benny Ng <benny.tpng@gmail.com>
Benoit Chesneau <bchesneau@gmail.com>
@@ -634,6 +638,7 @@ Eng Zer Jun <engzerjun@gmail.com>
Enguerran <engcolson@gmail.com>
Eohyung Lee <liquidnuker@gmail.com>
epeterso <epeterson@breakpoint-labs.com>
er0k <er0k@er0k.net>
Eric Barch <barch@tomesoftware.com>
Eric Curtin <ericcurtin17@gmail.com>
Eric G. Noriega <enoriega@vizuri.com>
@@ -754,6 +759,7 @@ Félix Baylac-Jacqué <baylac.felix@gmail.com>
Félix Cantournet <felix.cantournet@cloudwatt.com>
Gabe Rosenhouse <gabe@missionst.com>
Gabor Nagy <mail@aigeruth.hu>
Gabriel Adrian Samfira <gsamfira@cloudbasesolutions.com>
Gabriel Goller <gabrielgoller123@gmail.com>
Gabriel L. Somlo <gsomlo@gmail.com>
Gabriel Linder <linder.gabriel@gmail.com>
@@ -855,6 +861,7 @@ Hongbin Lu <hongbin034@gmail.com>
Hongxu Jia <hongxu.jia@windriver.com>
Honza Pokorny <me@honza.ca>
Hsing-Hui Hsu <hsinghui@amazon.com>
Hsing-Yu (David) Chen <davidhsingyuchen@gmail.com>
hsinko <21551195@zju.edu.cn>
Hu Keping <hukeping@huawei.com>
Hu Tao <hutao@cn.fujitsu.com>
@@ -887,6 +894,7 @@ Igor Dolzhikov <bluesriverz@gmail.com>
Igor Karpovich <i.karpovich@currencysolutions.com>
Iliana Weller <iweller@amazon.com>
Ilkka Laukkanen <ilkka@ilkka.io>
Illia Antypenko <ilya@antipenko.pp.ua>
Illo Abdulrahim <abdulrahim.illo@nokia.com>
Ilya Dmitrichenko <errordeveloper@gmail.com>
Ilya Gusev <mail@igusev.ru>
@@ -938,6 +946,7 @@ Jamie Hannaford <jamie@limetree.org>
Jamshid Afshar <jafshar@yahoo.com>
Jan Breig <git@pygos.space>
Jan Chren <dev.rindeal@gmail.com>
Jan Garcia <github-public@n-garcia.com>
Jan Götte <jaseg@jaseg.net>
Jan Keromnes <janx@linux.com>
Jan Koprowski <jan.koprowski@gmail.com>
@@ -1206,6 +1215,7 @@ Kimbro Staken <kstaken@kstaken.com>
Kir Kolyshkin <kolyshkin@gmail.com>
Kiran Gangadharan <kiran.daredevil@gmail.com>
Kirill SIbirev <l0kix2@gmail.com>
Kirk Easterson <kirk.easterson@gmail.com>
knappe <tyler.knappe@gmail.com>
Kohei Tsuruta <coheyxyz@gmail.com>
Koichi Shiraishi <k@zchee.io>
@@ -1240,10 +1250,12 @@ Lars Kellogg-Stedman <lars@redhat.com>
Lars R. Damerow <lars@pixar.com>
Lars-Magnus Skog <ralphtheninja@riseup.net>
Laszlo Meszaros <lacienator@gmail.com>
Laura Brehm <laurabrehm@hey.com>
Laura Frank <ljfrank@gmail.com>
Laurent Bernaille <laurent.bernaille@datadoghq.com>
Laurent Erignoux <lerignoux@gmail.com>
Laurie Voss <github@seldo.com>
Leandro Motta Barros <lmb@stackedboxes.org>
Leandro Siqueira <leandro.siqueira@gmail.com>
Lee Calcote <leecalcote@gmail.com>
Lee Chao <932819864@qq.com>
@@ -1563,6 +1575,7 @@ Nick Neisen <nwneisen@gmail.com>
Nick Parker <nikaios@gmail.com>
Nick Payne <nick@kurai.co.uk>
Nick Russo <nicholasjamesrusso@gmail.com>
Nick Santos <nick.santos@docker.com>
Nick Stenning <nick.stenning@digital.cabinet-office.gov.uk>
Nick Stinemates <nick@stinemates.org>
Nick Wood <nwood@microsoft.com>
@@ -1584,6 +1597,7 @@ NikolaMandic <mn080202@gmail.com>
Nikolas Garofil <nikolas.garofil@uantwerpen.be>
Nikolay Edigaryev <edigaryev@gmail.com>
Nikolay Milovanov <nmil@itransformers.net>
ningmingxiao <ning.mingxiao@zte.com.cn>
Nirmal Mehta <nirmalkmehta@gmail.com>
Nishant Totla <nishanttotla@gmail.com>
NIWA Hideyuki <niwa.niwa@nifty.ne.jp>
@@ -1615,6 +1629,7 @@ Omri Shiv <Omri.Shiv@teradata.com>
Onur Filiz <onur.filiz@microsoft.com>
Oriol Francès <oriolfa@gmail.com>
Oscar Bonilla <6f6231@gmail.com>
oscar.chen <2972789494@qq.com>
Oskar Niburski <oskarniburski@gmail.com>
Otto Kekäläinen <otto@seravo.fi>
Ouyang Liduo <oyld0210@163.com>
@@ -1822,6 +1837,7 @@ Rory Hunter <roryhunter2@gmail.com>
Rory McCune <raesene@gmail.com>
Ross Boucher <rboucher@gmail.com>
Rovanion Luckey <rovanion.luckey@gmail.com>
Roy Reznik <roy@wiz.io>
Royce Remer <royceremer@gmail.com>
Rozhnov Alexandr <nox73@ya.ru>
Rudolph Gottesheim <r.gottesheim@loot.at>
@@ -2271,6 +2287,7 @@ Xiaoyu Zhang <zhang.xiaoyu33@zte.com.cn>
xichengliudui <1693291525@qq.com>
xiekeyang <xiekeyang@huawei.com>
Ximo Guanter Gonzálbez <joaquin.guantergonzalbez@telefonica.com>
xin.li <xin.li@daocloud.io>
Xinbo Weng <xihuanbo_0521@zju.edu.cn>
Xinfeng Liu <xinfeng.liu@gmail.com>
Xinzi Zhou <imdreamrunner@gmail.com>
@@ -2282,6 +2299,7 @@ Yahya <ya7yaz@gmail.com>
yalpul <yalpul@gmail.com>
YAMADA Tsuyoshi <tyamada@minimum2scp.org>
Yamasaki Masahide <masahide.y@gmail.com>
Yamazaki Masashi <masi19bw@gmail.com>
Yan Feng <yanfeng2@huawei.com>
Yan Zhu <yanzhu@alauda.io>
Yang Bai <hamo.by@gmail.com>
+1 -1
View File
@@ -3,7 +3,7 @@ package api // import "github.com/docker/docker/api"
// Common constants for daemon and client.
const (
// DefaultVersion of Current REST API
DefaultVersion = "1.42"
DefaultVersion = "1.43"
// NoBaseImageSpecifier is the symbol used by the FROM
// command to specify that no base image is to be used.
+71 -78
View File
@@ -19,10 +19,10 @@ produces:
consumes:
- "application/json"
- "text/plain"
basePath: "/v1.42"
basePath: "/v1.43"
info:
title: "Docker Engine API"
version: "1.42"
version: "1.43"
x-logo:
url: "https://docs.docker.com/assets/images/logo-docker-main.png"
description: |
@@ -55,8 +55,8 @@ info:
the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
is returned.
If you omit the version-prefix, the current version of the API (v1.42) is used.
For example, calling `/info` is the same as calling `/v1.42/info`. Using the
If you omit the version-prefix, the current version of the API (v1.43) is used.
For example, calling `/info` is the same as calling `/v1.43/info`. Using the
API without a version-prefix is deprecated and will be removed in a future release.
Engine releases in the near future should support this version of the API,
@@ -976,6 +976,13 @@ definitions:
items:
type: "integer"
minimum: 0
Annotations:
type: "object"
description: |
Arbitrary non-identifying metadata attached to container and
provided to the runtime when the container is started.
additionalProperties:
type: "string"
# Applicable to UNIX platforms
CapAdd:
@@ -1122,6 +1129,7 @@ definitions:
remapping option is enabled.
ShmSize:
type: "integer"
format: "int64"
description: |
Size of `/dev/shm` in bytes. If omitted, the system uses 64MB.
minimum: 0
@@ -1610,6 +1618,34 @@ definitions:
"WorkDir": "/var/lib/docker/overlay2/ef749362d13333e65fc95c572eb525abbe0052e16e086cb64bc3b98ae9aa6d74/work"
}
FilesystemChange:
description: |
Change in the container's filesystem.
type: "object"
required: [Path, Kind]
properties:
Path:
description: |
Path to file or directory that has changed.
type: "string"
x-nullable: false
Kind:
$ref: "#/definitions/ChangeType"
ChangeType:
description: |
Kind of change
Can be one of:
- `0`: Modified ("C")
- `1`: Added ("A")
- `2`: Deleted ("D")
type: "integer"
format: "uint8"
enum: [0, 1, 2]
x-nullable: false
ImageInspect:
description: |
Information about an image in the local image cache.
@@ -1746,15 +1782,14 @@ definitions:
Total size of the image including all layers it is composed of.
In versions of Docker before v1.10, this field was calculated from
the image itself and all of its parent images. Docker v1.10 and up
store images self-contained, and no longer use a parent-chain, making
this field an equivalent of the Size field.
the image itself and all of its parent images. Images are now stored
self-contained, and no longer use a parent-chain, making this field
an equivalent of the Size field.
This field is kept for backward compatibility, but may be removed in
a future version of the API.
> **Deprecated**: this field is kept for backward compatibility, but
> will be removed in API v1.44.
type: "integer"
format: "int64"
x-nullable: false
example: 1239828
GraphDriver:
$ref: "#/definitions/GraphDriverData"
@@ -1802,7 +1837,6 @@ definitions:
- Created
- Size
- SharedSize
- VirtualSize
- Labels
- Containers
properties:
@@ -1888,19 +1922,17 @@ definitions:
x-nullable: false
example: 1239828
VirtualSize:
description: |
description: |-
Total size of the image including all layers it is composed of.
In versions of Docker before v1.10, this field was calculated from
the image itself and all of its parent images. Docker v1.10 and up
store images self-contained, and no longer use a parent-chain, making
this field an equivalent of the Size field.
the image itself and all of its parent images. Images are now stored
self-contained, and no longer use a parent-chain, making this field
an equivalent of the Size field.
This field is kept for backward compatibility, but may be removed in
a future version of the API.
Deprecated: this field is kept for backward compatibility, and will be removed in API v1.44.
type: "integer"
format: "int64"
x-nullable: false
example: 172064416
Labels:
description: "User-defined key/value metadata."
@@ -4652,7 +4684,8 @@ definitions:
example: false
OOMKilled:
description: |
Whether this container has been killed because it ran out of memory.
Whether a process within this container has been killed because it ran
out of memory since the container was last started.
type: "boolean"
example: false
Dead:
@@ -5035,7 +5068,7 @@ definitions:
Go runtime (`GOOS`).
Currently returned values are "linux" and "windows". A full list of
possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment).
possible values can be found in the [Go documentation](https://go.dev/doc/install/source#environment).
type: "string"
example: "linux"
Architecture:
@@ -5043,7 +5076,7 @@ definitions:
Hardware architecture of the host, as returned by the Go runtime
(`GOARCH`).
A full list of possible values can be found in the [Go documentation](https://golang.org/doc/install/source#environment).
A full list of possible values can be found in the [Go documentation](https://go.dev/doc/install/source#environment).
type: "string"
example: "x86_64"
NCPU:
@@ -5129,42 +5162,8 @@ definitions:
ServerVersion:
description: |
Version string of the daemon.
> **Note**: the [standalone Swarm API](https://docs.docker.com/swarm/swarm-api/)
> returns the Swarm version instead of the daemon version, for example
> `swarm/1.2.8`.
type: "string"
example: "17.06.0-ce"
ClusterStore:
description: |
URL of the distributed storage backend.
The storage backend is used for multihost networking (to store
network and endpoint information) and by the node discovery mechanism.
<p><br /></p>
> **Deprecated**: This field is only propagated when using standalone Swarm
> mode, and overlay networking using an external k/v store. Overlay
> networks with Swarm mode enabled use the built-in raft store, and
> this field will be empty.
type: "string"
example: "consul://consul.corp.example.com:8600/some/path"
ClusterAdvertise:
description: |
The network endpoint that the Engine advertises for the purpose of
node discovery. ClusterAdvertise is a `host:port` combination on which
the daemon is reachable by other hosts.
<p><br /></p>
> **Deprecated**: This field is only propagated when using standalone Swarm
> mode, and overlay networking using an external k/v store. Overlay
> networks with Swarm mode enabled use the built-in raft store, and
> this field will be empty.
type: "string"
example: "node5.corp.example.com:8000"
example: "24.0.2"
Runtimes:
description: |
List of [OCI compliant](https://github.com/opencontainers/runtime-spec)
@@ -5242,7 +5241,8 @@ definitions:
SecurityOptions:
description: |
List of security features that are enabled on the daemon, such as
apparmor, seccomp, SELinux, user-namespaces (userns), and rootless.
apparmor, seccomp, SELinux, user-namespaces (userns), rootless and
no-new-privileges.
Additional configuration options for each security feature may
be present, and are included as a comma-separated list of key/value
@@ -6875,9 +6875,9 @@ paths:
Returns which files in a container's filesystem have been added, deleted,
or modified. The `Kind` of modification can be one of:
- `0`: Modified
- `1`: Added
- `2`: Deleted
- `0`: Modified ("C")
- `1`: Added ("A")
- `2`: Deleted ("D")
operationId: "ContainerChanges"
produces: ["application/json"]
responses:
@@ -6886,22 +6886,7 @@ paths:
schema:
type: "array"
items:
type: "object"
x-go-name: "ContainerChangeResponseItem"
title: "ContainerChangeResponseItem"
description: "change item in response to ContainerChanges operation"
required: [Path, Kind]
properties:
Path:
description: "Path to file that has changed"
type: "string"
x-nullable: false
Kind:
description: "Kind of change"
type: "integer"
format: "uint8"
enum: [0, 1, 2]
x-nullable: false
$ref: "#/definitions/FilesystemChange"
examples:
application/json:
- Path: "/dev"
@@ -8228,7 +8213,7 @@ paths:
Available filters:
- `until=<duration>`: duration relative to daemon's time, during which build cache was not used, in Go's duration format (e.g., '24h')
- `until=<timestamp>` remove cache older than `<timestamp>`. The `<timestamp>` can be Unix timestamps, date formatted timestamps, or Go duration strings (e.g. `10m`, `1h30m`) computed relative to the daemon's local time.
- `id=<id>`
- `parent=<id>`
- `type=<string>`
@@ -9911,7 +9896,9 @@ paths:
Id: "22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30"
Warning: ""
403:
description: "operation not supported for pre-defined networks"
description: |
Forbidden operation. This happens when trying to create a network named after a pre-defined network,
or when trying to create an overlay network on a daemon which is not part of a Swarm cluster.
schema:
$ref: "#/definitions/ErrorResponse"
404:
@@ -10374,6 +10361,12 @@ paths:
default if omitted.
required: true
type: "string"
- name: "force"
in: "query"
description: |
Force disable a plugin even if still in use.
required: false
type: "boolean"
tags: ["Plugin"]
/plugins/{name}/upgrade:
post:
+5 -20
View File
@@ -1,22 +1,7 @@
package types // import "github.com/docker/docker/api/types"
import "github.com/docker/docker/api/types/registry"
// 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.
// This field is deprecated and will be removed in a later
// version of docker.
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"`
}
// AuthConfig contains authorization information for connecting to a Registry.
//
// Deprecated: use github.com/docker/docker/api/types/registry.AuthConfig
type AuthConfig = registry.AuthConfig
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/api/types/registry"
units "github.com/docker/go-units"
)
@@ -180,7 +181,7 @@ type ImageBuildOptions struct {
// at all (nil). See the parsing of buildArgs in
// api/server/router/build/build_routes.go for even more info.
BuildArgs map[string]*string
AuthConfigs map[string]AuthConfig
AuthConfigs map[string]registry.AuthConfig
Context io.Reader
Labels map[string]string
// squash the resulting image's layers to the parent
+2 -2
View File
@@ -3,7 +3,7 @@ package types // import "github.com/docker/docker/api/types"
import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
specs "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// configs holds structs used for internal communication between the
@@ -16,7 +16,7 @@ type ContainerCreateConfig struct {
Config *container.Config
HostConfig *container.HostConfig
NetworkingConfig *network.NetworkingConfig
Platform *specs.Platform
Platform *ocispec.Platform
AdjustCPUShares bool
}
@@ -0,0 +1,6 @@
package container
// ContainerChangeResponseItem change item in response to ContainerChanges operation
//
// Deprecated: use [FilesystemChange].
type ContainerChangeResponseItem = FilesystemChange
+15
View File
@@ -0,0 +1,15 @@
package container
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// ChangeType Kind of change
//
// Can be one of:
//
// - `0`: Modified ("C")
// - `1`: Added ("A")
// - `2`: Deleted ("D")
//
// swagger:model ChangeType
type ChangeType uint8
+23
View File
@@ -0,0 +1,23 @@
package container
const (
// ChangeModify represents the modify operation.
ChangeModify ChangeType = 0
// ChangeAdd represents the add operation.
ChangeAdd ChangeType = 1
// ChangeDelete represents the delete operation.
ChangeDelete ChangeType = 2
)
func (ct ChangeType) String() string {
switch ct {
case ChangeModify:
return "C"
case ChangeAdd:
return "A"
case ChangeDelete:
return "D"
default:
return ""
}
}
@@ -1,20 +0,0 @@
package container // import "github.com/docker/docker/api/types/container"
// ----------------------------------------------------------------------------
// Code generated by `swagger generate operation`. DO NOT EDIT.
//
// See hack/generate-swagger-api.sh
// ----------------------------------------------------------------------------
// ContainerChangeResponseItem change item in response to ContainerChanges operation
// swagger:model ContainerChangeResponseItem
type ContainerChangeResponseItem struct {
// Kind of change
// Required: true
Kind uint8 `json:"Kind"`
// Path to file that has changed
// Required: true
Path string `json:"Path"`
}
-16
View File
@@ -1,16 +0,0 @@
package container // import "github.com/docker/docker/api/types/container"
// ContainerCreateCreatedBody OK response to ContainerCreate operation
//
// Deprecated: use CreateResponse
type ContainerCreateCreatedBody = CreateResponse
// ContainerWaitOKBody OK response to ContainerWait operation
//
// Deprecated: use WaitResponse
type ContainerWaitOKBody = WaitResponse
// ContainerWaitOKBodyError container waiting error, if any
//
// Deprecated: use WaitExitError
type ContainerWaitOKBodyError = WaitExitError
@@ -0,0 +1,19 @@
package container
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
// FilesystemChange Change in the container's filesystem.
//
// swagger:model FilesystemChange
type FilesystemChange struct {
// kind
// Required: true
Kind ChangeType `json:"Kind"`
// Path to file or directory that has changed.
//
// Required: true
Path string `json:"Path"`
}
@@ -101,7 +101,8 @@ func (n IpcMode) IsShareable() bool {
// IsContainer indicates whether the container uses another container's ipc namespace.
func (n IpcMode) IsContainer() bool {
return strings.HasPrefix(string(n), string(IPCModeContainer)+":")
_, ok := containerID(string(n))
return ok
}
// IsNone indicates whether container IpcMode is set to "none".
@@ -116,15 +117,14 @@ func (n IpcMode) IsEmpty() bool {
// Valid indicates whether the ipc mode is valid.
func (n IpcMode) Valid() bool {
// TODO(thaJeztah): align with PidMode, and consider container-mode without a container name/ID to be invalid.
return n.IsEmpty() || n.IsNone() || n.IsPrivate() || n.IsHost() || n.IsShareable() || n.IsContainer()
}
// Container returns the name of the container ipc stack is going to be used.
func (n IpcMode) Container() string {
if n.IsContainer() {
return strings.TrimPrefix(string(n), string(IPCModeContainer)+":")
}
return ""
func (n IpcMode) Container() (idOrName string) {
idOrName, _ = containerID(string(n))
return idOrName
}
// NetworkMode represents the container network stack.
@@ -147,17 +147,14 @@ func (n NetworkMode) IsPrivate() bool {
// IsContainer indicates whether container uses a container network stack.
func (n NetworkMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
return len(parts) > 1 && parts[0] == "container"
_, ok := containerID(string(n))
return ok
}
// ConnectedContainer is the id of the container which network this container is connected to.
func (n NetworkMode) ConnectedContainer() string {
parts := strings.SplitN(string(n), ":", 2)
if len(parts) > 1 {
return parts[1]
}
return ""
func (n NetworkMode) ConnectedContainer() (idOrName string) {
idOrName, _ = containerID(string(n))
return idOrName
}
// UserDefined indicates user-created network
@@ -178,18 +175,12 @@ func (n UsernsMode) IsHost() bool {
// IsPrivate indicates whether the container uses the a private userns.
func (n UsernsMode) IsPrivate() bool {
return !(n.IsHost())
return !n.IsHost()
}
// Valid indicates whether the userns is valid.
func (n UsernsMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
case "", "host":
default:
return false
}
return true
return n == "" || n.IsHost()
}
// CgroupSpec represents the cgroup to use for the container.
@@ -197,22 +188,20 @@ type CgroupSpec string
// IsContainer indicates whether the container is using another container cgroup
func (c CgroupSpec) IsContainer() bool {
parts := strings.SplitN(string(c), ":", 2)
return len(parts) > 1 && parts[0] == "container"
_, ok := containerID(string(c))
return ok
}
// Valid indicates whether the cgroup spec is valid.
func (c CgroupSpec) Valid() bool {
return c.IsContainer() || c == ""
// TODO(thaJeztah): align with PidMode, and consider container-mode without a container name/ID to be invalid.
return c == "" || c.IsContainer()
}
// Container returns the name of the container whose cgroup will be used.
func (c CgroupSpec) Container() string {
parts := strings.SplitN(string(c), ":", 2)
if len(parts) > 1 {
return parts[1]
}
return ""
// Container returns the ID or name of the container whose cgroup will be used.
func (c CgroupSpec) Container() (idOrName string) {
idOrName, _ = containerID(string(c))
return idOrName
}
// UTSMode represents the UTS namespace of the container.
@@ -220,7 +209,7 @@ type UTSMode string
// IsPrivate indicates whether the container uses its private UTS namespace.
func (n UTSMode) IsPrivate() bool {
return !(n.IsHost())
return !n.IsHost()
}
// IsHost indicates whether the container uses the host's UTS namespace.
@@ -230,13 +219,7 @@ func (n UTSMode) IsHost() bool {
// Valid indicates whether the UTS namespace is valid.
func (n UTSMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
case "", "host":
default:
return false
}
return true
return n == "" || n.IsHost()
}
// PidMode represents the pid namespace of the container.
@@ -254,32 +237,19 @@ func (n PidMode) IsHost() bool {
// IsContainer indicates whether the container uses a container's pid namespace.
func (n PidMode) IsContainer() bool {
parts := strings.SplitN(string(n), ":", 2)
return len(parts) > 1 && parts[0] == "container"
_, ok := containerID(string(n))
return ok
}
// Valid indicates whether the pid namespace is valid.
func (n PidMode) Valid() bool {
parts := strings.Split(string(n), ":")
switch mode := parts[0]; mode {
case "", "host":
case "container":
if len(parts) != 2 || parts[1] == "" {
return false
}
default:
return false
}
return true
return n == "" || n.IsHost() || validContainer(string(n))
}
// Container returns the name of the container whose pid namespace is going to be used.
func (n PidMode) Container() string {
parts := strings.SplitN(string(n), ":", 2)
if len(parts) > 1 {
return parts[1]
}
return ""
func (n PidMode) Container() (idOrName string) {
idOrName, _ = containerID(string(n))
return idOrName
}
// DeviceRequest represents a request for devices from a device driver.
@@ -408,16 +378,17 @@ type UpdateConfig struct {
// Portable information *should* appear in Config.
type HostConfig struct {
// Applicable to all platforms
Binds []string // List of volume bindings for this container
ContainerIDFile string // File (path) where the containerId is written
LogConfig LogConfig // Configuration of the logs for this container
NetworkMode NetworkMode // Network mode to use for the container
PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host
RestartPolicy RestartPolicy // Restart policy to be used for the container
AutoRemove bool // Automatically remove container when it exits
VolumeDriver string // Name of the volume driver used to mount volumes
VolumesFrom []string // List of volumes to take from other container
ConsoleSize [2]uint // Initial console size (height,width)
Binds []string // List of volume bindings for this container
ContainerIDFile string // File (path) where the containerId is written
LogConfig LogConfig // Configuration of the logs for this container
NetworkMode NetworkMode // Network mode to use for the container
PortBindings nat.PortMap // Port mapping between the exposed port (container) and the host
RestartPolicy RestartPolicy // Restart policy to be used for the container
AutoRemove bool // Automatically remove container when it exits
VolumeDriver string // Name of the volume driver used to mount volumes
VolumesFrom []string // List of volumes to take from other container
ConsoleSize [2]uint // Initial console size (height,width)
Annotations map[string]string `json:",omitempty"` // Arbitrary non-identifying metadata attached to container and provided to the runtime
// Applicable to UNIX platforms
CapAdd strslice.StrSlice // List of kernel capabilities to add to the container
@@ -463,3 +434,23 @@ type HostConfig struct {
// Run a custom init inside the container, if null, use the daemon's configured settings
Init *bool `json:",omitempty"`
}
// containerID splits "container:<ID|name>" values. It returns the container
// ID or name, and whether an ID/name was found. It returns an empty string and
// a "false" if the value does not have a "container:" prefix. Further validation
// of the returned, including checking if the value is empty, should be handled
// by the caller.
func containerID(val string) (idOrName string, ok bool) {
k, v, hasSep := strings.Cut(val, ":")
if !hasSep || k != "container" {
return "", false
}
return v, true
}
// validContainer checks if the given value is a "container:" mode with
// a non-empty name/ID.
func validContainer(val string) bool {
id, ok := containerID(val)
return ok && id != ""
}
-14
View File
@@ -1,14 +0,0 @@
package types // import "github.com/docker/docker/api/types"
import "github.com/docker/docker/api/types/volume"
// Volume volume
//
// Deprecated: use github.com/docker/docker/api/types/volume.Volume
type Volume = volume.Volume
// VolumeUsageData Usage details about the volume. This information is used by the
// `GET /system/df` endpoint, and omitted in other endpoints.
//
// Deprecated: use github.com/docker/docker/api/types/volume.UsageData
type VolumeUsageData = volume.UsageData
+37
View File
@@ -0,0 +1,37 @@
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() {}
// unreachableCode is an error indicating that the code path was not expected to be reached.
type unreachableCode struct {
Filter string
Value []string
}
// System marks this error as ErrSystem
func (e unreachableCode) System() {}
func (e unreachableCode) Error() string {
return fmt.Sprintf("unreachable code reached for filter: %q with values: %s", e.Filter, e.Value)
}
+37 -14
View File
@@ -10,7 +10,6 @@ import (
"strings"
"github.com/docker/docker/api/types/versions"
"github.com/pkg/errors"
)
// Args stores a mapping of keys to a set of multiple values.
@@ -99,7 +98,7 @@ func FromJSON(p string) (Args, error) {
// Fallback to parsing arguments in the legacy slice format
deprecated := map[string][]string{}
if legacyErr := json.Unmarshal(raw, &deprecated); legacyErr != nil {
return args, invalidFilter{errors.Wrap(err, "invalid filter")}
return args, &invalidFilter{}
}
args.fields = deprecatedArgs(deprecated)
@@ -163,13 +162,13 @@ func (args Args) MatchKVList(key string, sources map[string]string) bool {
}
for value := range fieldValues {
testKV := strings.SplitN(value, "=", 2)
testK, testV, hasValue := strings.Cut(value, "=")
v, ok := sources[testKV[0]]
v, ok := sources[testK]
if !ok {
return false
}
if len(testKV) == 2 && testKV[1] != v {
if hasValue && testV != v {
return false
}
}
@@ -196,6 +195,38 @@ func (args Args) Match(field, source string) bool {
return false
}
// GetBoolOrDefault returns a boolean value of the key if the key is present
// and is intepretable 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"]
conflicting := isFalse && isTrue
invalid := !isFalse && !isTrue
if conflicting || invalid {
return defaultValue, &invalidFilter{key, args.Get(key)}
} else if isFalse {
return false, nil
} else if isTrue {
return true, nil
}
// This code shouldn't be reached.
return defaultValue, &unreachableCode{Filter: key, Value: args.Get(key)}
}
// 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]
@@ -246,20 +277,12 @@ func (args Args) Contains(field string) bool {
return ok
}
type invalidFilter struct{ error }
func (e invalidFilter) Error() string {
return e.error.Error()
}
func (invalidFilter) InvalidParameter() {}
// 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{errors.New("invalid filter '" + name + "'")}
return &invalidFilter{name, nil}
}
}
return nil
+9
View File
@@ -0,0 +1,9 @@
package image
import ocispec "github.com/opencontainers/image-spec/specs-go/v1"
// GetImageOpts holds parameters to inspect an image.
type GetImageOpts struct {
Platform *ocispec.Platform
Details bool
}
+5 -8
View File
@@ -85,13 +85,10 @@ type ImageSummary struct {
// Total size of the image including all layers it is composed of.
//
// In versions of Docker before v1.10, this field was calculated from
// the image itself and all of its parent images. Docker v1.10 and up
// store images self-contained, and no longer use a parent-chain, making
// this field an equivalent of the Size field.
// the image itself and all of its parent images. Images are now stored
// self-contained, and no longer use a parent-chain, making this field
// an equivalent of the Size field.
//
// This field is kept for backward compatibility, but may be removed in
// a future version of the API.
//
// Required: true
VirtualSize int64 `json:"VirtualSize"`
// Deprecated: this field is kept for backward compatibility, and will be removed in API v1.44.
VirtualSize int64 `json:"VirtualSize,omitempty"`
}
+99
View File
@@ -0,0 +1,99 @@
package registry // import "github.com/docker/docker/api/types/registry"
import (
"encoding/base64"
"encoding/json"
"io"
"strings"
"github.com/pkg/errors"
)
// AuthHeader is the name of the header used to send encoded registry
// authorization credentials for registry operations (push/pull).
const AuthHeader = "X-Registry-Auth"
// 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.
// This field is deprecated and will be removed in a later
// version of docker.
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.
//
// For details on base64url encoding, see:
// - 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.
//
// For details on base64url encoding, see:
// - 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.
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{errors.Wrap(err, "invalid X-Registry-Auth header")}
}
type errInvalidParameter struct{ error }
func (errInvalidParameter) InvalidParameter() {}
func (e errInvalidParameter) Cause() error { return e.error }
func (e errInvalidParameter) Unwrap() error { return e.error }
+3 -3
View File
@@ -4,7 +4,7 @@ import (
"encoding/json"
"net"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// ServiceConfig stores daemon registry services configuration.
@@ -113,8 +113,8 @@ type SearchResults struct {
type DistributionInspect struct {
// Descriptor contains information about the manifest, including
// the content addressable digest
Descriptor v1.Descriptor
Descriptor ocispec.Descriptor
// Platforms contains the list of platforms supported by the image,
// obtained by parsing the manifest
Platforms []v1.Platform
Platforms []ocispec.Platform
}
+20 -20
View File
@@ -95,37 +95,37 @@ func GetTimestamp(value string, reference time.Time) (string, error) {
return fmt.Sprintf("%d.%09d", t.Unix(), int64(t.Nanosecond())), nil
}
// ParseTimestamps returns seconds and nanoseconds from a timestamp that has the
// format "%d.%09d", time.Unix(), int64(time.Nanosecond()))
// if the incoming nanosecond portion is longer or shorter than 9 digits it is
// converted to nanoseconds. The expectation is that the seconds and
// seconds will be used to create a time variable. For example:
// ParseTimestamps returns seconds and nanoseconds from a timestamp that has
// the format ("%d.%09d", time.Unix(), int64(time.Nanosecond())).
// If the incoming nanosecond portion is longer than 9 digits it is truncated.
// The expectation is that the seconds and nanoseconds will be used to create a
// time variable. For example:
//
// seconds, nanoseconds, err := ParseTimestamp("1136073600.000000001",0)
// if err == nil since := time.Unix(seconds, nanoseconds)
// seconds, nanoseconds, _ := ParseTimestamp("1136073600.000000001",0)
// since := time.Unix(seconds, nanoseconds)
//
// returns seconds as def(aultSeconds) if value == ""
func ParseTimestamps(value string, def int64) (int64, int64, error) {
// returns seconds as defaultSeconds if value == ""
func ParseTimestamps(value string, defaultSeconds int64) (seconds int64, nanoseconds int64, err error) {
if value == "" {
return def, 0, nil
return defaultSeconds, 0, nil
}
return parseTimestamp(value)
}
func parseTimestamp(value string) (int64, int64, error) {
sa := strings.SplitN(value, ".", 2)
s, err := strconv.ParseInt(sa[0], 10, 64)
func parseTimestamp(value string) (sec int64, nsec int64, err error) {
s, n, ok := strings.Cut(value, ".")
sec, err = strconv.ParseInt(s, 10, 64)
if err != nil {
return s, 0, err
return sec, 0, err
}
if len(sa) != 2 {
return s, 0, nil
if !ok {
return sec, 0, nil
}
n, err := strconv.ParseInt(sa[1], 10, 64)
nsec, err = strconv.ParseInt(n, 10, 64)
if err != nil {
return s, n, err
return sec, nsec, err
}
// should already be in nanoseconds but just in case convert n to nanoseconds
n = int64(float64(n) * math.Pow(float64(10), float64(9-len(sa[1]))))
return s, n, nil
nsec = int64(float64(nsec) * math.Pow(float64(10), float64(9-len(n))))
return sec, nsec, nil
}
+18 -16
View File
@@ -123,9 +123,8 @@ type ImageInspect struct {
// store images self-contained, and no longer use a parent-chain, making
// this field an equivalent of the Size field.
//
// This field is kept for backward compatibility, but may be removed in
// a future version of the API.
VirtualSize int64 // TODO(thaJeztah): deprecate this field
// Deprecated: Unused in API 1.43 and up, but kept for backward compatibility with older API versions.
VirtualSize int64 `json:"VirtualSize,omitempty"`
// GraphDriver holds information about the storage driver used to store the
// container's and image's filesystem.
@@ -297,8 +296,6 @@ type Info struct {
Labels []string
ExperimentalBuild bool
ServerVersion string
ClusterStore string `json:",omitempty"` // Deprecated: host-discovery and overlay networks with external k/v stores are deprecated
ClusterAdvertise string `json:",omitempty"` // Deprecated: host-discovery and overlay networks with external k/v stores are deprecated
Runtimes map[string]Runtime
DefaultRuntime string
Swarm swarm.Info
@@ -350,20 +347,19 @@ func DecodeSecurityOptions(opts []string) ([]SecurityOpt, error) {
continue
}
secopt := SecurityOpt{}
split := strings.Split(opt, ",")
for _, s := range split {
kv := strings.SplitN(s, "=", 2)
if len(kv) != 2 {
for _, s := range strings.Split(opt, ",") {
k, v, ok := strings.Cut(s, "=")
if !ok {
return nil, fmt.Errorf("invalid security option %q", s)
}
if kv[0] == "" || kv[1] == "" {
if k == "" || v == "" {
return nil, errors.New("invalid empty security option")
}
if kv[0] == "name" {
secopt.Name = kv[1]
if k == "name" {
secopt.Name = v
continue
}
secopt.Options = append(secopt.Options, KeyValue{Key: kv[0], Value: kv[1]})
secopt.Options = append(secopt.Options, KeyValue{Key: k, Value: v})
}
so = append(so, secopt)
}
@@ -656,12 +652,18 @@ type Checkpoint struct {
// Runtime describes an OCI runtime
type Runtime struct {
Path string `json:"path"`
// "Legacy" runtime configuration for runc-compatible runtimes.
Path string `json:"path,omitempty"`
Args []string `json:"runtimeArgs,omitempty"`
// Shimv2 runtime configuration. Mutually exclusive with the legacy config above.
Type string `json:"runtimeType,omitempty"`
Options map[string]interface{} `json:"options,omitempty"`
// This is exposed here only for internal use
// It is not currently supported to specify custom shim configs
Shim *ShimConfig `json:"-"`
ShimConfig *ShimConfig `json:"-"`
}
// ShimConfig is used by runtime to configure containerd shims
+4 -4
View File
@@ -16,11 +16,11 @@ func compare(v1, v2 string) int {
otherTab = strings.Split(v2, ".")
)
max := len(currTab)
if len(otherTab) > max {
max = len(otherTab)
maxVer := len(currTab)
if len(otherTab) > maxVer {
maxVer = len(otherTab)
}
for i := 0; i < max; i++ {
for i := 0; i < maxVer; i++ {
var currInt, otherInt int
if len(currTab) > i {
-11
View File
@@ -1,11 +0,0 @@
package volume // import "github.com/docker/docker/api/types/volume"
// VolumeCreateBody Volume configuration
//
// Deprecated: use CreateOptions
type VolumeCreateBody = CreateOptions
// VolumeListOKBody Volume list response
//
// Deprecated: use ListResponse
type VolumeListOKBody = ListResponse
+5 -5
View File
@@ -3,8 +3,8 @@ package client // import "github.com/docker/docker/client"
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@@ -23,12 +23,12 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
if opts.All {
query.Set("all", "1")
}
query.Set("keep-storage", fmt.Sprintf("%d", opts.KeepStorage))
filters, err := filters.ToJSON(opts.Filters)
query.Set("keep-storage", strconv.Itoa(int(opts.KeepStorage)))
f, err := filters.ToJSON(opts.Filters)
if err != nil {
return nil, errors.Wrap(err, "prune could not marshal filters option")
}
query.Set("filters", filters)
query.Set("filters", f)
serverResp, err := cli.post(ctx, "/build/prune", query, nil, nil)
defer ensureReaderClosed(serverResp)
@@ -38,7 +38,7 @@ func (cli *Client) BuildCachePrune(ctx context.Context, opts types.BuildCachePru
}
if err := json.NewDecoder(serverResp.body).Decode(&report); err != nil {
return nil, fmt.Errorf("Error retrieving disk usage: %v", err)
return nil, errors.Wrap(err, "error retrieving disk usage")
}
return &report, nil
+47 -13
View File
@@ -6,9 +6,10 @@ https://docs.docker.com/engine/api/
# Usage
You use the library by creating a client object and calling methods on it. The
client can be created either from environment variables with NewClientWithOpts(client.FromEnv),
or configured manually with NewClient().
You use the library by constructing a client object using [NewClientWithOpts]
and calling methods on it. The client can be configured from environment
variables by passing the [FromEnv] option, or configured manually by passing any
of the other available [Opts].
For example, to list running containers (the equivalent of "docker ps"):
@@ -55,6 +56,36 @@ import (
"github.com/pkg/errors"
)
// DummyHost is a hostname used for local communication.
//
// It acts as a valid formatted hostname for local connections (such as "unix://"
// or "npipe://") which do not require a hostname. It should never be resolved,
// but uses the special-purpose ".localhost" TLD (as defined in [RFC 2606, Section 2]
// and [RFC 6761, Section 6.3]).
//
// [RFC 7230, Section 5.4] defines that an empty header must be used for such
// cases:
//
// If the authority component is missing or undefined for the target URI,
// then a client MUST send a Host header field with an empty field-value.
//
// However, [Go stdlib] enforces the semantics of HTTP(S) over TCP, does not
// allow an empty header to be used, and requires req.URL.Scheme to be either
// "http" or "https".
//
// For further details, refer to:
//
// - https://github.com/docker/engine-api/issues/189
// - https://github.com/golang/go/issues/13624
// - https://github.com/golang/go/issues/61076
// - https://github.com/moby/moby/issues/45935
//
// [RFC 2606, Section 2]: https://www.rfc-editor.org/rfc/rfc2606.html#section-2
// [RFC 6761, Section 6.3]: https://www.rfc-editor.org/rfc/rfc6761#section-6.3
// [RFC 7230, Section 5.4]: https://datatracker.ietf.org/doc/html/rfc7230#section-5.4
// [Go stdlib]: https://github.com/golang/go/blob/6244b1946bc2101b01955468f1be502dbadd6807/src/net/http/transport.go#L558-L569
const DummyHost = "api.moby.localhost"
// ErrRedirect is the error returned by checkRedirect when the request is non-GET.
var ErrRedirect = errors.New("unexpected redirect in response")
@@ -125,7 +156,12 @@ func CheckRedirect(req *http.Request, via []*http.Request) error {
// client.WithAPIVersionNegotiation(),
// )
func NewClientWithOpts(ops ...Opt) (*Client, error) {
client, err := defaultHTTPClient(DefaultDockerHost)
hostURL, err := ParseHostURL(DefaultDockerHost)
if err != nil {
return nil, err
}
client, err := defaultHTTPClient(hostURL)
if err != nil {
return nil, err
}
@@ -133,8 +169,8 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
host: DefaultDockerHost,
version: api.DefaultVersion,
client: client,
proto: defaultProto,
addr: defaultAddr,
proto: hostURL.Scheme,
addr: hostURL.Host,
}
for _, op := range ops {
@@ -160,13 +196,12 @@ func NewClientWithOpts(ops ...Opt) (*Client, error) {
return c, nil
}
func defaultHTTPClient(host string) (*http.Client, error) {
hostURL, err := ParseHostURL(host)
func defaultHTTPClient(hostURL *url.URL) (*http.Client, error) {
transport := &http.Transport{}
err := sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
if err != nil {
return nil, err
}
transport := &http.Transport{}
_ = sockets.ConfigureTransport(transport, hostURL.Scheme, hostURL.Host)
return &http.Client{
Transport: transport,
CheckRedirect: CheckRedirect,
@@ -282,13 +317,12 @@ func (cli *Client) HTTPClient() *http.Client {
// ParseHostURL parses a url string, validates the string is a host url, and
// returns the parsed URL
func ParseHostURL(host string) (*url.URL, error) {
protoAddrParts := strings.SplitN(host, "://", 2)
if len(protoAddrParts) == 1 {
proto, addr, ok := strings.Cut(host, "://")
if !ok || addr == "" {
return nil, errors.Errorf("unable to parse docker host `%s`", host)
}
var basePath string
proto, addr := protoAddrParts[0], protoAddrParts[1]
if proto == "tcp" {
parsed, err := url.Parse("tcp://" + addr)
if err != nil {
+6 -2
View File
@@ -9,7 +9,11 @@ import "net/http"
// 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
//
// 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))
}
@@ -17,7 +21,7 @@ func NewClient(host string, version string, client *http.Client, httpHeaders map
// NewEnvClient initializes a new API client based on environment variables.
// See FromEnv for a list of support environment variables.
//
// Deprecated: use NewClientWithOpts(FromEnv)
// Deprecated: use [NewClientWithOpts] passing the [FromEnv] option.
func NewEnvClient() (*Client, error) {
return NewClientWithOpts(FromEnv)
}
+2 -5
View File
@@ -1,11 +1,8 @@
//go:build linux || freebsd || openbsd || netbsd || darwin || solaris || illumos || dragonfly
// +build linux freebsd openbsd netbsd darwin solaris illumos dragonfly
//go:build !windows
// +build !windows
package client // import "github.com/docker/docker/client"
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
// (EnvOverrideHost) environment variable is unset or empty.
const DefaultDockerHost = "unix:///var/run/docker.sock"
const defaultProto = "unix"
const defaultAddr = "/var/run/docker.sock"
-3
View File
@@ -3,6 +3,3 @@ package client // import "github.com/docker/docker/client"
// DefaultDockerHost defines OS-specific default host if the DOCKER_HOST
// (EnvOverrideHost) environment variable is unset or empty.
const DefaultDockerHost = "npipe:////./pipe/docker_engine"
const defaultProto = "npipe"
const defaultAddr = "//./pipe/docker_engine"
+3 -3
View File
@@ -9,7 +9,7 @@ import (
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/versions"
specs "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
type configWrapper struct {
@@ -20,7 +20,7 @@ type configWrapper struct {
// 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 *specs.Platform, containerName string) (container.CreateResponse, error) {
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
if err := cli.NewVersionError("1.25", "stop timeout"); config != nil && config.StopTimeout != nil && err != nil {
@@ -75,7 +75,7 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
// 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 *specs.Platform) string {
func formatPlatform(platform *ocispec.Platform) string {
if platform == nil {
return ""
}
+2 -2
View File
@@ -9,8 +9,8 @@ import (
)
// ContainerDiff shows differences in a container filesystem since it was started.
func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]container.ContainerChangeResponseItem, error) {
var changes []container.ContainerChangeResponseItem
func (cli *Client) ContainerDiff(ctx context.Context, containerID string) ([]container.FilesystemChange, error) {
var changes []container.FilesystemChange
serverResp, err := cli.get(ctx, "/containers/"+containerID+"/changes", url.Values{}, nil)
defer ensureReaderClosed(serverResp)
+4 -4
View File
@@ -5,13 +5,13 @@ import (
"encoding/json"
"net/url"
registrytypes "github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/registry"
)
// DistributionInspect returns the image digest with the full manifest.
func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registrytypes.DistributionInspect, error) {
func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegistryAuth string) (registry.DistributionInspect, error) {
// Contact the registry to retrieve digest and platform information
var distributionInspect registrytypes.DistributionInspect
var distributionInspect registry.DistributionInspect
if image == "" {
return distributionInspect, objectNotFoundError{object: "distribution", id: image}
}
@@ -23,7 +23,7 @@ func (cli *Client) DistributionInspect(ctx context.Context, image, encodedRegist
if encodedRegistryAuth != "" {
headers = map[string][]string{
"X-Registry-Auth": {encodedRegistryAuth},
registry.AuthHeader: {encodedRegistryAuth},
}
}
-25
View File
@@ -58,31 +58,6 @@ func (e objectNotFoundError) Error() string {
return fmt.Sprintf("Error: No such %s: %s", e.object, e.id)
}
// IsErrUnauthorized returns true if the error is caused
// when a remote registry authentication fails
//
// Deprecated: use errdefs.IsUnauthorized
func IsErrUnauthorized(err error) bool {
return errdefs.IsUnauthorized(err)
}
type pluginPermissionDenied struct {
name string
}
func (e pluginPermissionDenied) Error() string {
return "Permission denied while installing plugin " + e.name
}
// IsErrNotImplemented returns true if the error is a NotImplemented error.
// This is returned by the API when a requested feature has not been
// implemented.
//
// Deprecated: use errdefs.IsNotImplemented
func IsErrNotImplemented(err error) bool {
return errdefs.IsNotImplemented(err)
}
// NewVersionError returns an error if the APIVersion required
// if less than the current supported version
func (cli *Client) NewVersionError(APIrequired, feature string) error {
+4 -9
View File
@@ -23,14 +23,10 @@ func (cli *Client) postHijacked(ctx context.Context, path string, query url.Valu
if err != nil {
return types.HijackedResponse{}, err
}
apiPath := cli.getAPIPath(ctx, path, query)
req, err := http.NewRequest(http.MethodPost, apiPath, bodyEncoded)
req, err := cli.buildRequest(http.MethodPost, cli.getAPIPath(ctx, path, query), bodyEncoded, headers)
if err != nil {
return types.HijackedResponse{}, err
}
req = cli.addHeaders(req, headers)
conn, mediaType, err := cli.setupHijackConn(ctx, req, "tcp")
if err != nil {
return types.HijackedResponse{}, err
@@ -64,7 +60,6 @@ func fallbackDial(proto, addr string, tlsConfig *tls.Config) (net.Conn, error) {
}
func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto string) (net.Conn, string, error) {
req.Host = cli.addr
req.Header.Set("Connection", "Upgrade")
req.Header.Set("Upgrade", proto)
@@ -80,8 +75,8 @@ func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto
// state. Setting TCP KeepAlive on the socket connection will prohibit
// ECONNTIMEOUT unless the socket connection truly is broken
if tcpConn, ok := conn.(*net.TCPConn); ok {
tcpConn.SetKeepAlive(true)
tcpConn.SetKeepAlivePeriod(30 * time.Second)
_ = tcpConn.SetKeepAlive(true)
_ = tcpConn.SetKeepAlivePeriod(30 * time.Second)
}
clientconn := httputil.NewClientConn(conn, nil)
@@ -96,7 +91,7 @@ func (cli *Client) setupHijackConn(ctx context.Context, req *http.Request, proto
return nil, "", err
}
if resp.StatusCode != http.StatusSwitchingProtocols {
resp.Body.Close()
_ = resp.Body.Close()
return nil, "", fmt.Errorf("unable to upgrade to %s, received %d", proto, resp.StatusCode)
}
}
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
)
// ImageCreate creates a new image based on the parent options.
@@ -32,6 +33,6 @@ func (cli *Client) ImageCreate(ctx context.Context, parentReference string, opti
}
func (cli *Client) tryImageCreate(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
return cli.post(ctx, "/images/create", query, nil, headers)
}
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
)
@@ -49,6 +50,6 @@ func (cli *Client) ImagePush(ctx context.Context, image string, options types.Im
}
func (cli *Client) tryImagePush(ctx context.Context, imageID string, query url.Values, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
return cli.post(ctx, "/images/"+imageID+"/push", query, nil, headers)
}
+1 -1
View File
@@ -48,6 +48,6 @@ func (cli *Client) ImageSearch(ctx context.Context, term string, options types.I
}
func (cli *Client) tryImageSearch(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
return cli.get(ctx, "/images/search", query, headers)
}
+5 -5
View File
@@ -15,7 +15,7 @@ import (
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/api/types/volume"
specs "github.com/opencontainers/image-spec/specs-go/v1"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)
// CommonAPIClient is the common methods between stable and experimental versions of APIClient.
@@ -47,8 +47,8 @@ type CommonAPIClient interface {
type ContainerAPIClient interface {
ContainerAttach(ctx context.Context, container string, options types.ContainerAttachOptions) (types.HijackedResponse, error)
ContainerCommit(ctx context.Context, container string, options types.ContainerCommitOptions) (types.IDResponse, error)
ContainerCreate(ctx context.Context, config *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, platform *specs.Platform, containerName string) (container.CreateResponse, error)
ContainerDiff(ctx context.Context, container string) ([]container.ContainerChangeResponseItem, 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, config types.ExecStartCheck) (types.HijackedResponse, error)
ContainerExecCreate(ctx context.Context, container string, config types.ExecConfig) (types.IDResponse, error)
ContainerExecInspect(ctx context.Context, execID string) (types.ContainerExecInspect, error)
@@ -166,7 +166,7 @@ type SwarmAPIClient interface {
type SystemAPIClient interface {
Events(ctx context.Context, options types.EventsOptions) (<-chan events.Message, <-chan error)
Info(ctx context.Context) (types.Info, error)
RegistryLogin(ctx context.Context, auth types.AuthConfig) (registry.AuthenticateOKBody, 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)
}
@@ -176,7 +176,7 @@ 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, filter filters.Args) (volume.ListResponse, 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) (types.VolumesPruneReport, error)
VolumeUpdate(ctx context.Context, volumeID string, version swarm.Version, options volume.UpdateOptions) error
+1 -2
View File
@@ -5,13 +5,12 @@ import (
"encoding/json"
"net/url"
"github.com/docker/docker/api/types"
"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 types.AuthConfig) (registry.AuthenticateOKBody, error) {
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)
+3 -3
View File
@@ -64,10 +64,10 @@ func parsePingResponse(cli *Client, resp serverResponse) (types.Ping, error) {
ping.BuilderVersion = types.BuilderVersion(bv)
}
if si := resp.header.Get("Swarm"); si != "" {
parts := strings.SplitN(si, "/", 2)
state, role, _ := strings.Cut(si, "/")
ping.SwarmStatus = &swarm.Status{
NodeState: swarm.LocalNodeState(parts[0]),
ControlAvailable: len(parts) == 2 && parts[1] == "manager",
NodeState: swarm.LocalNodeState(state),
ControlAvailable: role == "manager",
}
}
err := cli.checkResponseErr(resp)
+4 -3
View File
@@ -8,6 +8,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/errdefs"
"github.com/pkg/errors"
)
@@ -67,12 +68,12 @@ func (cli *Client) PluginInstall(ctx context.Context, name string, options types
}
func (cli *Client) tryPluginPrivileges(ctx context.Context, query url.Values, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
return cli.get(ctx, "/plugins/privileges", query, headers)
}
func (cli *Client) tryPluginPull(ctx context.Context, query url.Values, privileges types.PluginPrivileges, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
return cli.post(ctx, "/plugins/pull", query, privileges, headers)
}
@@ -106,7 +107,7 @@ func (cli *Client) checkPluginPermissions(ctx context.Context, query url.Values,
return nil, err
}
if !accept {
return nil, pluginPermissionDenied{options.RemoteRef}
return nil, errors.Errorf("permission denied while installing plugin %s", options.RemoteRef)
}
}
return privileges, nil
+3 -1
View File
@@ -3,11 +3,13 @@ package client // import "github.com/docker/docker/client"
import (
"context"
"io"
"github.com/docker/docker/api/types/registry"
)
// PluginPush pushes a plugin to a registry
func (cli *Client) PluginPush(ctx context.Context, name string, registryAuth string) (io.ReadCloser, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
resp, err := cli.post(ctx, "/plugins/"+name+"/push", nil, nil, headers)
if err != nil {
return nil, err
+2 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/pkg/errors"
)
@@ -34,6 +35,6 @@ func (cli *Client) PluginUpgrade(ctx context.Context, name string, options types
}
func (cli *Client) tryPluginUpgrade(ctx context.Context, query url.Values, privileges types.PluginPrivileges, name, registryAuth string) (serverResponse, error) {
headers := map[string][]string{"X-Registry-Auth": {registryAuth}}
headers := map[string][]string{registry.AuthHeader: {registryAuth}}
return cli.post(ctx, "/plugins/"+name+"/upgrade", query, privileges, headers)
}
+4 -6
View File
@@ -96,16 +96,14 @@ func (cli *Client) buildRequest(method, path string, body io.Reader, headers hea
return nil, err
}
req = cli.addHeaders(req, headers)
req.URL.Scheme = cli.scheme
req.URL.Host = cli.addr
if cli.proto == "unix" || cli.proto == "npipe" {
// For local communications, it doesn't matter what the host is. We just
// need a valid and meaningful host name. (See #189)
req.Host = "docker"
// Override host header for non-tcp connections.
req.Host = DummyHost
}
req.URL.Host = cli.addr
req.URL.Scheme = cli.scheme
if expectedPayload && req.Header.Get("Content-Type") == "" {
req.Header.Set("Content-Type", "text/plain")
}
+2 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
@@ -21,7 +22,7 @@ func (cli *Client) ServiceCreate(ctx context.Context, service swarm.ServiceSpec,
}
if options.EncodedRegistryAuth != "" {
headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
}
// Make sure containerSpec is not nil when no runtime is set or the runtime is set to container
+2 -1
View File
@@ -6,6 +6,7 @@ import (
"net/url"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/api/types/swarm"
)
@@ -23,7 +24,7 @@ func (cli *Client) ServiceUpdate(ctx context.Context, serviceID string, version
}
if options.EncodedRegistryAuth != "" {
headers["X-Registry-Auth"] = []string{options.EncodedRegistryAuth}
headers[registry.AuthHeader] = []string{options.EncodedRegistryAuth}
}
if options.RegistryAuthFrom != "" {
+3 -3
View File
@@ -10,13 +10,13 @@ import (
)
// VolumeList returns the volumes configured in the docker host.
func (cli *Client) VolumeList(ctx context.Context, filter filters.Args) (volume.ListResponse, error) {
func (cli *Client) VolumeList(ctx context.Context, options volume.ListOptions) (volume.ListResponse, error) {
var volumes volume.ListResponse
query := url.Values{}
if filter.Len() > 0 {
if options.Filters.Len() > 0 {
//nolint:staticcheck // ignore SA1019 for old code
filterJSON, err := filters.ToParamWithVersion(cli.version, filter)
filterJSON, err := filters.ToParamWithVersion(cli.version, options.Filters)
if err != nil {
return volumes, err
}
-133
View File
@@ -1,133 +0,0 @@
// Package ipamutils provides utility functions for ipam management
package ipamutils
import (
"fmt"
"net"
"sync"
)
var (
// PredefinedLocalScopeDefaultNetworks contains a list of 31 IPv4 private networks with host size 16 and 12
// (172.17-31.x.x/16, 192.168.x.x/20) which do not overlap with the networks in `PredefinedGlobalScopeDefaultNetworks`
PredefinedLocalScopeDefaultNetworks []*net.IPNet
// PredefinedGlobalScopeDefaultNetworks contains a list of 64K IPv4 private networks with host size 8
// (10.x.x.x/24) which do not overlap with the networks in `PredefinedLocalScopeDefaultNetworks`
PredefinedGlobalScopeDefaultNetworks []*net.IPNet
mutex sync.Mutex
localScopeDefaultNetworks = []*NetworkToSplit{{"172.17.0.0/16", 16}, {"172.18.0.0/16", 16}, {"172.19.0.0/16", 16},
{"172.20.0.0/14", 16}, {"172.24.0.0/14", 16}, {"172.28.0.0/14", 16},
{"192.168.0.0/16", 20}}
globalScopeDefaultNetworks = []*NetworkToSplit{{"10.0.0.0/8", 24}}
)
// NetworkToSplit represent a network that has to be split in chunks with mask length Size.
// Each subnet in the set is derived from the Base pool. Base is to be passed
// in CIDR format.
// Example: a Base "10.10.0.0/16 with Size 24 will define the set of 256
// 10.10.[0-255].0/24 address pools
type NetworkToSplit struct {
Base string `json:"base"`
Size int `json:"size"`
}
func init() {
var err error
if PredefinedGlobalScopeDefaultNetworks, err = splitNetworks(globalScopeDefaultNetworks); err != nil {
panic("failed to initialize the global scope default address pool: " + err.Error())
}
if PredefinedLocalScopeDefaultNetworks, err = splitNetworks(localScopeDefaultNetworks); err != nil {
panic("failed to initialize the local scope default address pool: " + err.Error())
}
}
// configDefaultNetworks configures local as well global default pool based on input
func configDefaultNetworks(defaultAddressPool []*NetworkToSplit, result *[]*net.IPNet) error {
mutex.Lock()
defer mutex.Unlock()
defaultNetworks, err := splitNetworks(defaultAddressPool)
if err != nil {
return err
}
*result = defaultNetworks
return nil
}
// GetGlobalScopeDefaultNetworks returns PredefinedGlobalScopeDefaultNetworks
func GetGlobalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return PredefinedGlobalScopeDefaultNetworks
}
// GetLocalScopeDefaultNetworks returns PredefinedLocalScopeDefaultNetworks
func GetLocalScopeDefaultNetworks() []*net.IPNet {
mutex.Lock()
defer mutex.Unlock()
return PredefinedLocalScopeDefaultNetworks
}
// ConfigGlobalScopeDefaultNetworks configures global default pool.
// Ideally this will be called from SwarmKit as part of swarm init
func ConfigGlobalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
if defaultAddressPool == nil {
defaultAddressPool = globalScopeDefaultNetworks
}
return configDefaultNetworks(defaultAddressPool, &PredefinedGlobalScopeDefaultNetworks)
}
// ConfigLocalScopeDefaultNetworks configures local default pool.
// Ideally this will be called during libnetwork init
func ConfigLocalScopeDefaultNetworks(defaultAddressPool []*NetworkToSplit) error {
if defaultAddressPool == nil {
return nil
}
return configDefaultNetworks(defaultAddressPool, &PredefinedLocalScopeDefaultNetworks)
}
// splitNetworks takes a slice of networks, split them accordingly and returns them
func splitNetworks(list []*NetworkToSplit) ([]*net.IPNet, error) {
localPools := make([]*net.IPNet, 0, len(list))
for _, p := range list {
_, b, err := net.ParseCIDR(p.Base)
if err != nil {
return nil, fmt.Errorf("invalid base pool %q: %v", p.Base, err)
}
ones, _ := b.Mask.Size()
if p.Size <= 0 || p.Size < ones {
return nil, fmt.Errorf("invalid pools size: %d", p.Size)
}
localPools = append(localPools, splitNetwork(p.Size, b)...)
}
return localPools, nil
}
func splitNetwork(size int, base *net.IPNet) []*net.IPNet {
one, bits := base.Mask.Size()
mask := net.CIDRMask(size, bits)
n := 1 << uint(size-one)
s := uint(bits - size)
list := make([]*net.IPNet, 0, n)
for i := 0; i < n; i++ {
ip := copyIP(base.IP)
addIntToIP(ip, uint(i<<s))
list = append(list, &net.IPNet{IP: ip, Mask: mask})
}
return list
}
func copyIP(from net.IP) net.IP {
ip := make([]byte, len(from))
copy(ip, from)
return ip
}
func addIntToIP(array net.IP, ordinal uint) {
for i := len(array) - 1; i >= 0; i-- {
array[i] |= (byte)(ordinal & 0xff)
ordinal >>= 8
}
}
-84
View File
@@ -1,84 +0,0 @@
package opts
import (
"encoding/csv"
"encoding/json"
"fmt"
"strconv"
"strings"
types "github.com/docker/docker/libnetwork/ipamutils"
)
// PoolsOpt is a Value type for parsing the default address pools definitions
type PoolsOpt struct {
Values []*types.NetworkToSplit
}
// UnmarshalJSON fills values structure info from JSON input
func (p *PoolsOpt) UnmarshalJSON(raw []byte) error {
return json.Unmarshal(raw, &(p.Values))
}
// Set predefined pools
func (p *PoolsOpt) Set(value string) error {
csvReader := csv.NewReader(strings.NewReader(value))
fields, err := csvReader.Read()
if err != nil {
return err
}
poolsDef := types.NetworkToSplit{}
for _, field := range fields {
parts := strings.SplitN(field, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid field '%s' must be a key=value pair", field)
}
key := strings.ToLower(parts[0])
value := strings.ToLower(parts[1])
switch key {
case "base":
poolsDef.Base = value
case "size":
size, err := strconv.Atoi(value)
if err != nil {
return fmt.Errorf("invalid size value: %q (must be integer): %v", value, err)
}
poolsDef.Size = size
default:
return fmt.Errorf("unexpected key '%s' in '%s'", key, field)
}
}
p.Values = append(p.Values, &poolsDef)
return nil
}
// Type returns the type of this option
func (p *PoolsOpt) Type() string {
return "pool-options"
}
// String returns a string repr of this option
func (p *PoolsOpt) String() string {
var pools []string
for _, pool := range p.Values {
repr := fmt.Sprintf("%s %d", pool.Base, pool.Size)
pools = append(pools, repr)
}
return strings.Join(pools, ", ")
}
// Value returns the mounts
func (p *PoolsOpt) Value() []*types.NetworkToSplit {
return p.Values
}
// Name returns the flag name of this option
func (p *PoolsOpt) Name() string {
return "default-address-pools"
}
-30
View File
@@ -1,30 +0,0 @@
package opts // import "github.com/docker/docker/opts"
import (
"os"
"strings"
"github.com/pkg/errors"
)
// ValidateEnv validates an environment variable and returns it.
// If no value is specified, it obtains its value from the current environment
//
// As on ParseEnvFile and related to #16585, environment variable names
// are not validate whatsoever, it's up to application inside docker
// to validate them or not.
//
// The only validation here is to check if name is empty, per #25099
func ValidateEnv(val string) (string, error) {
arr := strings.SplitN(val, "=", 2)
if arr[0] == "" {
return "", errors.New("invalid environment variable: " + val)
}
if len(arr) > 1 {
return val, nil
}
if envVal, ok := os.LookupEnv(arr[0]); ok {
return arr[0] + "=" + envVal, nil
}
return val, nil
}
-186
View File
@@ -1,186 +0,0 @@
package opts // import "github.com/docker/docker/opts"
import (
"net"
"net/url"
"path/filepath"
"strconv"
"strings"
"github.com/docker/docker/pkg/homedir"
"github.com/pkg/errors"
)
const (
// DefaultHTTPPort Default HTTP Port used if only the protocol is provided to -H flag e.g. dockerd -H tcp://
// These are the IANA registered port numbers for use with Docker
// see http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=docker
DefaultHTTPPort = 2375 // Default HTTP Port
// DefaultTLSHTTPPort Default HTTP Port used when TLS enabled
DefaultTLSHTTPPort = 2376 // Default TLS encrypted HTTP Port
// DefaultUnixSocket Path for the unix socket.
// Docker daemon by default always listens on the default unix socket
DefaultUnixSocket = "/var/run/docker.sock"
// DefaultTCPHost constant defines the default host string used by docker on Windows
DefaultTCPHost = "tcp://" + DefaultHTTPHost + ":2375"
// DefaultTLSHost constant defines the default host string used by docker for TLS sockets
DefaultTLSHost = "tcp://" + DefaultHTTPHost + ":2376"
// DefaultNamedPipe defines the default named pipe used by docker on Windows
DefaultNamedPipe = `//./pipe/docker_engine`
// HostGatewayName is the string value that can be passed
// to the IPAddr section in --add-host that is replaced by
// the value of HostGatewayIP daemon config value
HostGatewayName = "host-gateway"
)
// ValidateHost validates that the specified string is a valid host and returns it.
func ValidateHost(val string) (string, error) {
host := strings.TrimSpace(val)
// The empty string means default and is not handled by parseDaemonHost
if host != "" {
_, err := parseDaemonHost(host)
if err != nil {
return val, err
}
}
// Note: unlike most flag validators, we don't return the mutated value here
// we need to know what the user entered later (using ParseHost) to adjust for TLS
return val, nil
}
// ParseHost and set defaults for a Daemon host string.
// defaultToTLS is preferred over defaultToUnixXDG.
func ParseHost(defaultToTLS, defaultToUnixXDG bool, val string) (string, error) {
host := strings.TrimSpace(val)
if host == "" {
if defaultToTLS {
host = DefaultTLSHost
} else if defaultToUnixXDG {
runtimeDir, err := homedir.GetRuntimeDir()
if err != nil {
return "", err
}
socket := filepath.Join(runtimeDir, "docker.sock")
host = "unix://" + socket
} else {
host = DefaultHost
}
} else {
var err error
host, err = parseDaemonHost(host)
if err != nil {
return val, err
}
}
return host, nil
}
// parseDaemonHost parses the specified address and returns an address that will be used as the host.
// Depending on the address specified, this may return one of the global Default* strings defined in hosts.go.
func parseDaemonHost(addr string) (string, error) {
addrParts := strings.SplitN(addr, "://", 2)
if len(addrParts) == 1 && addrParts[0] != "" {
addrParts = []string{"tcp", addrParts[0]}
}
switch addrParts[0] {
case "tcp":
return ParseTCPAddr(addr, DefaultTCPHost)
case "unix":
return parseSimpleProtoAddr("unix", addrParts[1], DefaultUnixSocket)
case "npipe":
return parseSimpleProtoAddr("npipe", addrParts[1], DefaultNamedPipe)
case "fd":
return addr, nil
default:
return "", errors.Errorf("invalid bind address (%s): unsupported proto '%s'", addr, addrParts[0])
}
}
// parseSimpleProtoAddr parses and validates that the specified address is a valid
// socket address for simple protocols like unix and npipe. It returns a formatted
// socket address, either using the address parsed from addr, or the contents of
// defaultAddr if addr is a blank string.
func parseSimpleProtoAddr(proto, addr, defaultAddr string) (string, error) {
addr = strings.TrimPrefix(addr, proto+"://")
if strings.Contains(addr, "://") {
return "", errors.Errorf("invalid proto, expected %s: %s", proto, addr)
}
if addr == "" {
addr = defaultAddr
}
return proto + "://" + addr, nil
}
// ParseTCPAddr parses and validates that the specified address is a valid TCP
// address. It returns a formatted TCP address, either using the address parsed
// from tryAddr, or the contents of defaultAddr if tryAddr is a blank string.
// tryAddr is expected to have already been Trim()'d
// defaultAddr must be in the full `tcp://host:port` form
func ParseTCPAddr(tryAddr string, defaultAddr string) (string, error) {
def, err := parseTCPAddr(defaultAddr, true)
if err != nil {
return "", errors.Wrapf(err, "invalid default address (%s)", defaultAddr)
}
addr, err := parseTCPAddr(tryAddr, false)
if err != nil {
return "", errors.Wrapf(err, "invalid bind address (%s)", tryAddr)
}
host := addr.Hostname()
if host == "" {
host = def.Hostname()
}
port := addr.Port()
if port == "" {
port = def.Port()
}
return "tcp://" + net.JoinHostPort(host, port), nil
}
// parseTCPAddr parses the given addr and validates if it is in the expected
// format. If strict is enabled, the address must contain a scheme (tcp://),
// a host (or IP-address) and a port number.
func parseTCPAddr(address string, strict bool) (*url.URL, error) {
if !strict && !strings.Contains(address, "://") {
address = "tcp://" + address
}
parsedURL, err := url.Parse(address)
if err != nil {
return nil, err
}
if parsedURL.Scheme != "tcp" {
return nil, errors.Errorf("unsupported proto '%s'", parsedURL.Scheme)
}
if parsedURL.Path != "" {
return nil, errors.New("should not contain a path element")
}
if strict && parsedURL.Host == "" {
return nil, errors.New("no host or IP address")
}
if parsedURL.Port() != "" || strict {
if p, err := strconv.Atoi(parsedURL.Port()); err != nil || p == 0 {
return nil, errors.Errorf("invalid port: %s", parsedURL.Port())
}
}
return parsedURL, nil
}
// ValidateExtraHost validates that the specified string is a valid extrahost and returns it.
// ExtraHost is in the form of name:ip where the ip has to be a valid ip (IPv4 or IPv6).
func ValidateExtraHost(val string) (string, error) {
// allow for IPv6 addresses in extra hosts by only splitting on first ":"
arr := strings.SplitN(val, ":", 2)
if len(arr) != 2 || len(arr[0]) == 0 {
return "", errors.Errorf("bad format for add-host: %q", val)
}
// Skip IPaddr validation for special "host-gateway" string
if arr[1] != HostGatewayName {
if _, err := ValidateIPAddress(arr[1]); err != nil {
return "", errors.Errorf("invalid IP address in add-host: %q", arr[1])
}
}
return val, nil
}
-12
View File
@@ -1,12 +0,0 @@
//go:build !windows
// +build !windows
package opts // import "github.com/docker/docker/opts"
const (
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
DefaultHTTPHost = "localhost"
// DefaultHost constant defines the default host string used by docker on other hosts than Windows
DefaultHost = "unix://" + DefaultUnixSocket
)
-60
View File
@@ -1,60 +0,0 @@
package opts // import "github.com/docker/docker/opts"
const (
// TODO Windows. Identify bug in GOLang 1.5.1+ and/or Windows Server 2016 TP5.
//
// On Windows, this mitigates a problem with the default options of running
// a docker client against a local docker daemon on TP5.
//
// What was found that if the default host is "localhost", even if the client
// (and daemon as this is local) is not physically on a network, and the DNS
// cache is flushed (ipconfig /flushdns), then the client will pause for
// exactly one second when connecting to the daemon for calls. For example
// using docker run windowsservercore cmd, the CLI will send a create followed
// by an attach. You see the delay between the attach finishing and the attach
// being seen by the daemon.
//
// Here's some daemon debug logs with additional debug spew put in. The
// AfterWriteJSON log is the very last thing the daemon does as part of the
// create call. The POST /attach is the second CLI call. Notice the second
// time gap.
//
// time="2015-11-06T13:38:37.259627400-08:00" level=debug msg="After createRootfs"
// time="2015-11-06T13:38:37.263626300-08:00" level=debug msg="After setHostConfig"
// time="2015-11-06T13:38:37.267631200-08:00" level=debug msg="before createContainerPl...."
// time="2015-11-06T13:38:37.271629500-08:00" level=debug msg=ToDiskLocking....
// time="2015-11-06T13:38:37.275643200-08:00" level=debug msg="loggin event...."
// time="2015-11-06T13:38:37.277627600-08:00" level=debug msg="logged event...."
// time="2015-11-06T13:38:37.279631800-08:00" level=debug msg="In defer func"
// time="2015-11-06T13:38:37.282628100-08:00" level=debug msg="After daemon.create"
// time="2015-11-06T13:38:37.286651700-08:00" level=debug msg="return 2"
// time="2015-11-06T13:38:37.289629500-08:00" level=debug msg="Returned from daemon.ContainerCreate"
// time="2015-11-06T13:38:37.311629100-08:00" level=debug msg="After WriteJSON"
// ... 1 second gap here....
// time="2015-11-06T13:38:38.317866200-08:00" level=debug msg="Calling POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach"
// time="2015-11-06T13:38:38.326882500-08:00" level=info msg="POST /v1.22/containers/984758282b842f779e805664b2c95d563adc9a979c8a3973e68c807843ee4757/attach?stderr=1&stdin=1&stdout=1&stream=1"
//
// We suspect this is either a bug introduced in GOLang 1.5.1, or that a change
// in GOLang 1.5.1 (from 1.4.3) is exposing a bug in Windows. In theory,
// the Windows networking stack is supposed to resolve "localhost" internally,
// without hitting DNS, or even reading the hosts file (which is why localhost
// is commented out in the hosts file on Windows).
//
// We have validated that working around this using the actual IPv4 localhost
// address does not cause the delay.
//
// This does not occur with the docker client built with 1.4.3 on the same
// Windows build, regardless of whether the daemon is built using 1.5.1
// or 1.4.3. It does not occur on Linux. We also verified we see the same thing
// on a cross-compiled Windows binary (from Linux).
//
// Final note: This is a mitigation, not a 'real' fix. It is still susceptible
// to the delay if a user were to do 'docker run -H=tcp://localhost:2375...'
// explicitly.
// DefaultHTTPHost Default HTTP Host used if only port is provided to -H flag e.g. dockerd -H tcp://:8080
DefaultHTTPHost = "127.0.0.1"
// DefaultHost constant defines the default host string used by docker on Windows
DefaultHost = "npipe://" + DefaultNamedPipe
)
-348
View File
@@ -1,348 +0,0 @@
package opts // import "github.com/docker/docker/opts"
import (
"fmt"
"net"
"path"
"regexp"
"strings"
units "github.com/docker/go-units"
)
var (
alphaRegexp = regexp.MustCompile(`[a-zA-Z]`)
domainRegexp = regexp.MustCompile(`^(:?(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9]))(:?\.(:?[a-zA-Z0-9]|(:?[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])))*)\.?\s*$`)
)
// ListOpts holds a list of values and a validation function.
type ListOpts struct {
values *[]string
validator ValidatorFctType
}
// NewListOpts creates a new ListOpts with the specified validator.
func NewListOpts(validator ValidatorFctType) ListOpts {
var values []string
return *NewListOptsRef(&values, validator)
}
// NewListOptsRef creates a new ListOpts with the specified values and validator.
func NewListOptsRef(values *[]string, validator ValidatorFctType) *ListOpts {
return &ListOpts{
values: values,
validator: validator,
}
}
func (opts *ListOpts) String() string {
if len(*opts.values) == 0 {
return ""
}
return fmt.Sprintf("%v", *opts.values)
}
// Set validates if needed the input value and adds it to the
// internal slice.
func (opts *ListOpts) Set(value string) error {
if opts.validator != nil {
v, err := opts.validator(value)
if err != nil {
return err
}
value = v
}
*opts.values = append(*opts.values, value)
return nil
}
// Delete removes the specified element from the slice.
func (opts *ListOpts) Delete(key string) {
for i, k := range *opts.values {
if k == key {
*opts.values = append((*opts.values)[:i], (*opts.values)[i+1:]...)
return
}
}
}
// GetMap returns the content of values in a map in order to avoid
// duplicates.
func (opts *ListOpts) GetMap() map[string]struct{} {
ret := make(map[string]struct{})
for _, k := range *opts.values {
ret[k] = struct{}{}
}
return ret
}
// GetAll returns the values of slice.
func (opts *ListOpts) GetAll() []string {
return *opts.values
}
// GetAllOrEmpty returns the values of the slice
// or an empty slice when there are no values.
func (opts *ListOpts) GetAllOrEmpty() []string {
v := *opts.values
if v == nil {
return make([]string, 0)
}
return v
}
// Get checks the existence of the specified key.
func (opts *ListOpts) Get(key string) bool {
for _, k := range *opts.values {
if k == key {
return true
}
}
return false
}
// Len returns the amount of element in the slice.
func (opts *ListOpts) Len() int {
return len(*opts.values)
}
// Type returns a string name for this Option type
func (opts *ListOpts) Type() string {
return "list"
}
// WithValidator returns the ListOpts with validator set.
func (opts *ListOpts) WithValidator(validator ValidatorFctType) *ListOpts {
opts.validator = validator
return opts
}
// NamedOption is an interface that list and map options
// with names implement.
type NamedOption interface {
Name() string
}
// NamedListOpts is a ListOpts with a configuration name.
// This struct is useful to keep reference to the assigned
// field name in the internal configuration struct.
type NamedListOpts struct {
name string
ListOpts
}
var _ NamedOption = &NamedListOpts{}
// NewNamedListOptsRef creates a reference to a new NamedListOpts struct.
func NewNamedListOptsRef(name string, values *[]string, validator ValidatorFctType) *NamedListOpts {
return &NamedListOpts{
name: name,
ListOpts: *NewListOptsRef(values, validator),
}
}
// Name returns the name of the NamedListOpts in the configuration.
func (o *NamedListOpts) Name() string {
return o.name
}
// MapOpts holds a map of values and a validation function.
type MapOpts struct {
values map[string]string
validator ValidatorFctType
}
// Set validates if needed the input value and add it to the
// internal map, by splitting on '='.
func (opts *MapOpts) Set(value string) error {
if opts.validator != nil {
v, err := opts.validator(value)
if err != nil {
return err
}
value = v
}
vals := strings.SplitN(value, "=", 2)
if len(vals) == 1 {
(opts.values)[vals[0]] = ""
} else {
(opts.values)[vals[0]] = vals[1]
}
return nil
}
// GetAll returns the values of MapOpts as a map.
func (opts *MapOpts) GetAll() map[string]string {
return opts.values
}
func (opts *MapOpts) String() string {
return fmt.Sprintf("%v", opts.values)
}
// Type returns a string name for this Option type
func (opts *MapOpts) Type() string {
return "map"
}
// NewMapOpts creates a new MapOpts with the specified map of values and a validator.
func NewMapOpts(values map[string]string, validator ValidatorFctType) *MapOpts {
if values == nil {
values = make(map[string]string)
}
return &MapOpts{
values: values,
validator: validator,
}
}
// NamedMapOpts is a MapOpts struct with a configuration name.
// This struct is useful to keep reference to the assigned
// field name in the internal configuration struct.
type NamedMapOpts struct {
name string
MapOpts
}
var _ NamedOption = &NamedMapOpts{}
// NewNamedMapOpts creates a reference to a new NamedMapOpts struct.
func NewNamedMapOpts(name string, values map[string]string, validator ValidatorFctType) *NamedMapOpts {
return &NamedMapOpts{
name: name,
MapOpts: *NewMapOpts(values, validator),
}
}
// Name returns the name of the NamedMapOpts in the configuration.
func (o *NamedMapOpts) Name() string {
return o.name
}
// ValidatorFctType defines a validator function that returns a validated string and/or an error.
type ValidatorFctType func(val string) (string, error)
// ValidatorFctListType defines a validator function that returns a validated list of string and/or an error
type ValidatorFctListType func(val string) ([]string, error)
// ValidateIPAddress validates an Ip address.
func ValidateIPAddress(val string) (string, error) {
var ip = net.ParseIP(strings.TrimSpace(val))
if ip != nil {
return ip.String(), nil
}
return "", fmt.Errorf("%s is not an ip address", val)
}
// ValidateDNSSearch validates domain for resolvconf search configuration.
// A zero length domain is represented by a dot (.).
func ValidateDNSSearch(val string) (string, error) {
if val = strings.Trim(val, " "); val == "." {
return val, nil
}
return validateDomain(val)
}
func validateDomain(val string) (string, error) {
if alphaRegexp.FindString(val) == "" {
return "", fmt.Errorf("%s is not a valid domain", val)
}
ns := domainRegexp.FindSubmatch([]byte(val))
if len(ns) > 0 && len(ns[1]) < 255 {
return string(ns[1]), nil
}
return "", fmt.Errorf("%s is not a valid domain", val)
}
// ValidateLabel validates that the specified string is a valid label,
// it does not use the reserved namespaces com.docker.*, io.docker.*, org.dockerproject.*
// and returns it.
// Labels are in the form on key=value.
func ValidateLabel(val string) (string, error) {
if strings.Count(val, "=") < 1 {
return "", fmt.Errorf("bad attribute format: %s", val)
}
lowered := strings.ToLower(val)
if strings.HasPrefix(lowered, "com.docker.") || strings.HasPrefix(lowered, "io.docker.") ||
strings.HasPrefix(lowered, "org.dockerproject.") {
return "", fmt.Errorf(
"label %s is not allowed: the namespaces com.docker.*, io.docker.*, and org.dockerproject.* are reserved for internal use",
val)
}
return val, nil
}
// ValidateSingleGenericResource validates that a single entry in the
// generic resource list is valid.
// i.e 'GPU=UID1' is valid however 'GPU:UID1' or 'UID1' isn't
func ValidateSingleGenericResource(val string) (string, error) {
if strings.Count(val, "=") < 1 {
return "", fmt.Errorf("invalid node-generic-resource format `%s` expected `name=value`", val)
}
return val, nil
}
// ParseLink parses and validates the specified string as a link format (name:alias)
func ParseLink(val string) (string, string, error) {
if val == "" {
return "", "", fmt.Errorf("empty string specified for links")
}
arr := strings.Split(val, ":")
if len(arr) > 2 {
return "", "", fmt.Errorf("bad format for links: %s", val)
}
if len(arr) == 1 {
return val, val, nil
}
// This is kept because we can actually get a HostConfig with links
// from an already created container and the format is not `foo:bar`
// but `/foo:/c1/bar`
if strings.HasPrefix(arr[0], "/") {
_, alias := path.Split(arr[1])
return arr[0][1:], alias, nil
}
return arr[0], arr[1], nil
}
// MemBytes is a type for human readable memory bytes (like 128M, 2g, etc)
type MemBytes int64
// String returns the string format of the human readable memory bytes
func (m *MemBytes) String() string {
// NOTE: In spf13/pflag/flag.go, "0" is considered as "zero value" while "0 B" is not.
// We return "0" in case value is 0 here so that the default value is hidden.
// (Sometimes "default 0 B" is actually misleading)
if m.Value() != 0 {
return units.BytesSize(float64(m.Value()))
}
return "0"
}
// Set sets the value of the MemBytes by passing a string
func (m *MemBytes) Set(value string) error {
val, err := units.RAMInBytes(value)
*m = MemBytes(val)
return err
}
// Type returns the type
func (m *MemBytes) Type() string {
return "bytes"
}
// Value returns the value in int64
func (m *MemBytes) Value() int64 {
return int64(*m)
}
// UnmarshalJSON is the customized unmarshaler for MemBytes
func (m *MemBytes) UnmarshalJSON(s []byte) error {
if len(s) <= 2 || s[0] != '"' || s[len(s)-1] != '"' {
return fmt.Errorf("invalid size: %q", s)
}
val, err := units.RAMInBytes(string(s[1 : len(s)-1]))
*m = MemBytes(val)
return err
}
-79
View File
@@ -1,79 +0,0 @@
package opts // import "github.com/docker/docker/opts"
import (
"fmt"
"strings"
"github.com/docker/docker/api/types"
)
// RuntimeOpt defines a map of Runtimes
type RuntimeOpt struct {
name string
stockRuntimeName string
values *map[string]types.Runtime
}
// NewNamedRuntimeOpt creates a new RuntimeOpt
func NewNamedRuntimeOpt(name string, ref *map[string]types.Runtime, stockRuntime string) *RuntimeOpt {
if ref == nil {
ref = &map[string]types.Runtime{}
}
return &RuntimeOpt{name: name, values: ref, stockRuntimeName: stockRuntime}
}
// Name returns the name of the NamedListOpts in the configuration.
func (o *RuntimeOpt) Name() string {
return o.name
}
// Set validates and updates the list of Runtimes
func (o *RuntimeOpt) Set(val string) error {
parts := strings.SplitN(val, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid runtime argument: %s", val)
}
parts[0] = strings.TrimSpace(parts[0])
parts[1] = strings.TrimSpace(parts[1])
if parts[0] == "" || parts[1] == "" {
return fmt.Errorf("invalid runtime argument: %s", val)
}
parts[0] = strings.ToLower(parts[0])
if parts[0] == o.stockRuntimeName {
return fmt.Errorf("runtime name '%s' is reserved", o.stockRuntimeName)
}
if _, ok := (*o.values)[parts[0]]; ok {
return fmt.Errorf("runtime '%s' was already defined", parts[0])
}
(*o.values)[parts[0]] = types.Runtime{Path: parts[1]}
return nil
}
// String returns Runtime values as a string.
func (o *RuntimeOpt) String() string {
var out []string
for k := range *o.values {
out = append(out, k)
}
return fmt.Sprintf("%v", out)
}
// GetMap returns a map of Runtimes (name: path)
func (o *RuntimeOpt) GetMap() map[string]types.Runtime {
if o.values != nil {
return *o.values
}
return map[string]types.Runtime{}
}
// Type returns the type of the option
func (o *RuntimeOpt) Type() string {
return "runtime"
}
-81
View File
@@ -1,81 +0,0 @@
package opts // import "github.com/docker/docker/opts"
import (
"fmt"
units "github.com/docker/go-units"
)
// UlimitOpt defines a map of Ulimits
type UlimitOpt struct {
values *map[string]*units.Ulimit
}
// NewUlimitOpt creates a new UlimitOpt
func NewUlimitOpt(ref *map[string]*units.Ulimit) *UlimitOpt {
if ref == nil {
ref = &map[string]*units.Ulimit{}
}
return &UlimitOpt{ref}
}
// Set validates a Ulimit and sets its name as a key in UlimitOpt
func (o *UlimitOpt) Set(val string) error {
l, err := units.ParseUlimit(val)
if err != nil {
return err
}
(*o.values)[l.Name] = l
return nil
}
// String returns Ulimit values as a string.
func (o *UlimitOpt) String() string {
var out []string
for _, v := range *o.values {
out = append(out, v.String())
}
return fmt.Sprintf("%v", out)
}
// GetList returns a slice of pointers to Ulimits.
func (o *UlimitOpt) GetList() []*units.Ulimit {
var ulimits []*units.Ulimit
for _, v := range *o.values {
ulimits = append(ulimits, v)
}
return ulimits
}
// Type returns the option type
func (o *UlimitOpt) Type() string {
return "ulimit"
}
// NamedUlimitOpt defines a named map of Ulimits
type NamedUlimitOpt struct {
name string
UlimitOpt
}
var _ NamedOption = &NamedUlimitOpt{}
// NewNamedUlimitOpt creates a new NamedUlimitOpt
func NewNamedUlimitOpt(name string, ref *map[string]*units.Ulimit) *NamedUlimitOpt {
if ref == nil {
ref = &map[string]*units.Ulimit{}
}
return &NamedUlimitOpt{
name: name,
UlimitOpt: *NewUlimitOpt(ref),
}
}
// Name returns the option name
func (o *NamedUlimitOpt) Name() string {
return o.name
}
-1
View File
@@ -1 +0,0 @@
This code provides helper functions for dealing with archive files.
+222 -214
View File
@@ -1,3 +1,4 @@
// Package archive provides helper functions for dealing with archive files.
package archive // import "github.com/docker/docker/pkg/archive"
import (
@@ -11,6 +12,7 @@ import (
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"runtime"
"strconv"
@@ -28,7 +30,6 @@ import (
"github.com/moby/sys/sequential"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
exec "golang.org/x/sys/execabs"
)
// ImpliedDirectoryMode represents the mode (Unix permissions) applied to directories that are implied by files in a
@@ -111,16 +112,6 @@ const (
OverlayWhiteoutFormat
)
const (
modeISDIR = 040000 // Directory
modeISFIFO = 010000 // FIFO
modeISREG = 0100000 // Regular file
modeISLNK = 0120000 // Symbolic link
modeISBLK = 060000 // Block special file
modeISCHR = 020000 // Character special file
modeISSOCK = 0140000 // Socket
)
// IsArchivePath checks if the (possibly compressed) file at the given path
// starts with a tar file header.
func IsArchivePath(path string) bool {
@@ -469,9 +460,7 @@ func FileInfoHeaderNoLookups(fi os.FileInfo, link string) (*tar.Header, error) {
// but is safe to call from a chrooted process. The AccessTime and ChangeTime
// fields are not set in the returned header, ModTime is truncated to one-second
// precision, and the Uname and Gname fields are only set when fi is a FileInfo
// value returned from tar.Header.FileInfo(). Also, regardless of Go version,
// this function fills file type bits (e.g. hdr.Mode |= modeISDIR), which have
// been deleted since Go 1.9 archive/tar.
// value returned from tar.Header.FileInfo().
func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, error) {
hdr, err := FileInfoHeaderNoLookups(fi, link)
if err != nil {
@@ -481,36 +470,11 @@ func FileInfoHeader(name string, fi os.FileInfo, link string) (*tar.Header, erro
hdr.ModTime = hdr.ModTime.Truncate(time.Second)
hdr.AccessTime = time.Time{}
hdr.ChangeTime = time.Time{}
hdr.Mode = fillGo18FileTypeBits(int64(chmodTarEntry(os.FileMode(hdr.Mode))), fi)
hdr.Mode = int64(chmodTarEntry(os.FileMode(hdr.Mode)))
hdr.Name = canonicalTarName(name, fi.IsDir())
return hdr, nil
}
// fillGo18FileTypeBits fills type bits which have been removed on Go 1.9 archive/tar
// https://github.com/golang/go/commit/66b5a2f
func fillGo18FileTypeBits(mode int64, fi os.FileInfo) int64 {
fm := fi.Mode()
switch {
case fm.IsRegular():
mode |= modeISREG
case fi.IsDir():
mode |= modeISDIR
case fm&os.ModeSymlink != 0:
mode |= modeISLNK
case fm&os.ModeDevice != 0:
if fm&os.ModeCharDevice != 0 {
mode |= modeISCHR
} else {
mode |= modeISBLK
}
case fm&os.ModeNamedPipe != 0:
mode |= modeISFIFO
case fm&os.ModeSocket != 0:
mode |= modeISSOCK
}
return mode
}
// ReadSecurityXattrToTarHeader reads security.capability xattr from filesystem
// to a tar header
func ReadSecurityXattrToTarHeader(path string, hdr *tar.Header) error {
@@ -567,10 +531,17 @@ func newTarAppender(idMapping idtools.IdentityMapping, writer io.Writer, chownOp
}
}
// canonicalTarName provides a platform-independent and consistent posix-style
// CanonicalTarNameForPath canonicalizes relativePath to a POSIX-style path using
// forward slashes. It is an alias for filepath.ToSlash, which is a no-op on
// Linux and Unix.
func CanonicalTarNameForPath(relativePath string) string {
return filepath.ToSlash(relativePath)
}
// canonicalTarName provides a platform-independent and consistent POSIX-style
// path for files and directories to be archived regardless of the platform.
func canonicalTarName(name string, isDir bool) string {
name = CanonicalTarNameForPath(name)
name = filepath.ToSlash(name)
// suffix with '/' for directories
if isDir && !strings.HasSuffix(name, "/") {
@@ -850,10 +821,29 @@ func Tar(path string, compression Compression) (io.ReadCloser, error) {
// TarWithOptions creates an archive from the directory at `path`, only including files whose relative
// paths are included in `options.IncludeFiles` (if non-nil) or not in `options.ExcludePatterns`.
func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error) {
// Fix the source path to work with long path names. This is a no-op
// on platforms other than Windows.
srcPath = fixVolumePathPrefix(srcPath)
tb, err := NewTarballer(srcPath, options)
if err != nil {
return nil, err
}
go tb.Do()
return tb.Reader(), nil
}
// Tarballer is a lower-level interface to TarWithOptions which gives the caller
// control over which goroutine the archiving operation executes on.
type Tarballer struct {
srcPath string
options *TarOptions
pm *patternmatcher.PatternMatcher
pipeReader *io.PipeReader
pipeWriter *io.PipeWriter
compressWriter io.WriteCloser
whiteoutConverter tarWhiteoutConverter
}
// NewTarballer constructs a new tarballer. The arguments are the same as for
// TarWithOptions.
func NewTarballer(srcPath string, options *TarOptions) (*Tarballer, error) {
pm, err := patternmatcher.New(options.ExcludePatterns)
if err != nil {
return nil, err
@@ -871,183 +861,201 @@ func TarWithOptions(srcPath string, options *TarOptions) (io.ReadCloser, error)
return nil, err
}
go func() {
ta := newTarAppender(
options.IDMap,
compressWriter,
options.ChownOpts,
)
ta.WhiteoutConverter = whiteoutConverter
return &Tarballer{
// Fix the source path to work with long path names. This is a no-op
// on platforms other than Windows.
srcPath: fixVolumePathPrefix(srcPath),
options: options,
pm: pm,
pipeReader: pipeReader,
pipeWriter: pipeWriter,
compressWriter: compressWriter,
whiteoutConverter: whiteoutConverter,
}, nil
}
defer func() {
// Make sure to check the error on Close.
if err := ta.TarWriter.Close(); err != nil {
logrus.Errorf("Can't close tar writer: %s", err)
}
if err := compressWriter.Close(); err != nil {
logrus.Errorf("Can't close compress writer: %s", err)
}
if err := pipeWriter.Close(); err != nil {
logrus.Errorf("Can't close pipe writer: %s", err)
}
}()
// Reader returns the reader for the created archive.
func (t *Tarballer) Reader() io.ReadCloser {
return t.pipeReader
}
// this buffer is needed for the duration of this piped stream
defer pools.BufioWriter32KPool.Put(ta.Buffer)
// Do performs the archiving operation in the background. The resulting archive
// can be read from t.Reader(). Do should only be called once on each Tarballer
// instance.
func (t *Tarballer) Do() {
ta := newTarAppender(
t.options.IDMap,
t.compressWriter,
t.options.ChownOpts,
)
ta.WhiteoutConverter = t.whiteoutConverter
// In general we log errors here but ignore them because
// during e.g. a diff operation the container can continue
// mutating the filesystem and we can see transient errors
// from this
stat, err := os.Lstat(srcPath)
if err != nil {
return
defer func() {
// Make sure to check the error on Close.
if err := ta.TarWriter.Close(); err != nil {
logrus.Errorf("Can't close tar writer: %s", err)
}
if !stat.IsDir() {
// We can't later join a non-dir with any includes because the
// 'walk' will error if "file/." is stat-ed and "file" is not a
// directory. So, we must split the source path and use the
// basename as the include.
if len(options.IncludeFiles) > 0 {
logrus.Warn("Tar: Can't archive a file with includes")
}
dir, base := SplitPathDirEntry(srcPath)
srcPath = dir
options.IncludeFiles = []string{base}
if err := t.compressWriter.Close(); err != nil {
logrus.Errorf("Can't close compress writer: %s", err)
}
if len(options.IncludeFiles) == 0 {
options.IncludeFiles = []string{"."}
}
seen := make(map[string]bool)
for _, include := range options.IncludeFiles {
rebaseName := options.RebaseNames[include]
var (
parentMatchInfo []patternmatcher.MatchInfo
parentDirs []string
)
walkRoot := getWalkRoot(srcPath, include)
filepath.Walk(walkRoot, func(filePath string, f os.FileInfo, err error) error {
if err != nil {
logrus.Errorf("Tar: Can't stat file %s to tar: %s", srcPath, err)
return nil
}
relFilePath, err := filepath.Rel(srcPath, filePath)
if err != nil || (!options.IncludeSourceDir && relFilePath == "." && f.IsDir()) {
// Error getting relative path OR we are looking
// at the source directory path. Skip in both situations.
return nil
}
if options.IncludeSourceDir && include == "." && relFilePath != "." {
relFilePath = strings.Join([]string{".", relFilePath}, string(filepath.Separator))
}
skip := false
// If "include" is an exact match for the current file
// then even if there's an "excludePatterns" pattern that
// matches it, don't skip it. IOW, assume an explicit 'include'
// is asking for that file no matter what - which is true
// for some files, like .dockerignore and Dockerfile (sometimes)
if include != relFilePath {
for len(parentDirs) != 0 {
lastParentDir := parentDirs[len(parentDirs)-1]
if strings.HasPrefix(relFilePath, lastParentDir+string(os.PathSeparator)) {
break
}
parentDirs = parentDirs[:len(parentDirs)-1]
parentMatchInfo = parentMatchInfo[:len(parentMatchInfo)-1]
}
var matchInfo patternmatcher.MatchInfo
if len(parentMatchInfo) != 0 {
skip, matchInfo, err = pm.MatchesUsingParentResults(relFilePath, parentMatchInfo[len(parentMatchInfo)-1])
} else {
skip, matchInfo, err = pm.MatchesUsingParentResults(relFilePath, patternmatcher.MatchInfo{})
}
if err != nil {
logrus.Errorf("Error matching %s: %v", relFilePath, err)
return err
}
if f.IsDir() {
parentDirs = append(parentDirs, relFilePath)
parentMatchInfo = append(parentMatchInfo, matchInfo)
}
}
if skip {
// If we want to skip this file and its a directory
// then we should first check to see if there's an
// excludes pattern (e.g. !dir/file) that starts with this
// dir. If so then we can't skip this dir.
// Its not a dir then so we can just return/skip.
if !f.IsDir() {
return nil
}
// No exceptions (!...) in patterns so just skip dir
if !pm.Exclusions() {
return filepath.SkipDir
}
dirSlash := relFilePath + string(filepath.Separator)
for _, pat := range pm.Patterns() {
if !pat.Exclusion() {
continue
}
if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) {
// found a match - so can't skip this dir
return nil
}
}
// No matching exclusion dir so just skip dir
return filepath.SkipDir
}
if seen[relFilePath] {
return nil
}
seen[relFilePath] = true
// Rename the base resource.
if rebaseName != "" {
var replacement string
if rebaseName != string(filepath.Separator) {
// Special case the root directory to replace with an
// empty string instead so that we don't end up with
// double slashes in the paths.
replacement = rebaseName
}
relFilePath = strings.Replace(relFilePath, include, replacement, 1)
}
if err := ta.addTarFile(filePath, relFilePath); err != nil {
logrus.Errorf("Can't add file %s to tar: %s", filePath, err)
// if pipe is broken, stop writing tar stream to it
if err == io.ErrClosedPipe {
return err
}
}
return nil
})
if err := t.pipeWriter.Close(); err != nil {
logrus.Errorf("Can't close pipe writer: %s", err)
}
}()
return pipeReader, nil
// this buffer is needed for the duration of this piped stream
defer pools.BufioWriter32KPool.Put(ta.Buffer)
// In general we log errors here but ignore them because
// during e.g. a diff operation the container can continue
// mutating the filesystem and we can see transient errors
// from this
stat, err := os.Lstat(t.srcPath)
if err != nil {
return
}
if !stat.IsDir() {
// We can't later join a non-dir with any includes because the
// 'walk' will error if "file/." is stat-ed and "file" is not a
// directory. So, we must split the source path and use the
// basename as the include.
if len(t.options.IncludeFiles) > 0 {
logrus.Warn("Tar: Can't archive a file with includes")
}
dir, base := SplitPathDirEntry(t.srcPath)
t.srcPath = dir
t.options.IncludeFiles = []string{base}
}
if len(t.options.IncludeFiles) == 0 {
t.options.IncludeFiles = []string{"."}
}
seen := make(map[string]bool)
for _, include := range t.options.IncludeFiles {
rebaseName := t.options.RebaseNames[include]
var (
parentMatchInfo []patternmatcher.MatchInfo
parentDirs []string
)
walkRoot := getWalkRoot(t.srcPath, include)
filepath.WalkDir(walkRoot, func(filePath string, f os.DirEntry, err error) error {
if err != nil {
logrus.Errorf("Tar: Can't stat file %s to tar: %s", t.srcPath, err)
return nil
}
relFilePath, err := filepath.Rel(t.srcPath, filePath)
if err != nil || (!t.options.IncludeSourceDir && relFilePath == "." && f.IsDir()) {
// Error getting relative path OR we are looking
// at the source directory path. Skip in both situations.
return nil
}
if t.options.IncludeSourceDir && include == "." && relFilePath != "." {
relFilePath = strings.Join([]string{".", relFilePath}, string(filepath.Separator))
}
skip := false
// If "include" is an exact match for the current file
// then even if there's an "excludePatterns" pattern that
// matches it, don't skip it. IOW, assume an explicit 'include'
// is asking for that file no matter what - which is true
// for some files, like .dockerignore and Dockerfile (sometimes)
if include != relFilePath {
for len(parentDirs) != 0 {
lastParentDir := parentDirs[len(parentDirs)-1]
if strings.HasPrefix(relFilePath, lastParentDir+string(os.PathSeparator)) {
break
}
parentDirs = parentDirs[:len(parentDirs)-1]
parentMatchInfo = parentMatchInfo[:len(parentMatchInfo)-1]
}
var matchInfo patternmatcher.MatchInfo
if len(parentMatchInfo) != 0 {
skip, matchInfo, err = t.pm.MatchesUsingParentResults(relFilePath, parentMatchInfo[len(parentMatchInfo)-1])
} else {
skip, matchInfo, err = t.pm.MatchesUsingParentResults(relFilePath, patternmatcher.MatchInfo{})
}
if err != nil {
logrus.Errorf("Error matching %s: %v", relFilePath, err)
return err
}
if f.IsDir() {
parentDirs = append(parentDirs, relFilePath)
parentMatchInfo = append(parentMatchInfo, matchInfo)
}
}
if skip {
// If we want to skip this file and its a directory
// then we should first check to see if there's an
// excludes pattern (e.g. !dir/file) that starts with this
// dir. If so then we can't skip this dir.
// Its not a dir then so we can just return/skip.
if !f.IsDir() {
return nil
}
// No exceptions (!...) in patterns so just skip dir
if !t.pm.Exclusions() {
return filepath.SkipDir
}
dirSlash := relFilePath + string(filepath.Separator)
for _, pat := range t.pm.Patterns() {
if !pat.Exclusion() {
continue
}
if strings.HasPrefix(pat.String()+string(filepath.Separator), dirSlash) {
// found a match - so can't skip this dir
return nil
}
}
// No matching exclusion dir so just skip dir
return filepath.SkipDir
}
if seen[relFilePath] {
return nil
}
seen[relFilePath] = true
// Rename the base resource.
if rebaseName != "" {
var replacement string
if rebaseName != string(filepath.Separator) {
// Special case the root directory to replace with an
// empty string instead so that we don't end up with
// double slashes in the paths.
replacement = rebaseName
}
relFilePath = strings.Replace(relFilePath, include, replacement, 1)
}
if err := ta.addTarFile(filePath, relFilePath); err != nil {
logrus.Errorf("Can't add file %s to tar: %s", filePath, err)
// if pipe is broken, stop writing tar stream to it
if err == io.ErrClosedPipe {
return err
}
}
return nil
})
}
}
// Unpack unpacks the decompressedArchive to dest with options.
-8
View File
@@ -35,16 +35,8 @@ func getWalkRoot(srcPath string, include string) string {
return strings.TrimSuffix(srcPath, string(filepath.Separator)) + string(filepath.Separator) + include
}
// CanonicalTarNameForPath returns platform-specific filepath
// to canonical posix-style path for tar archival. p is relative
// path.
func CanonicalTarNameForPath(p string) string {
return p // already unix-style
}
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
func chmodTarEntry(perm os.FileMode) os.FileMode {
return perm // noop for unix as golang APIs provide perm bits correctly
}
+4 -14
View File
@@ -21,24 +21,14 @@ func getWalkRoot(srcPath string, include string) string {
return filepath.Join(srcPath, include)
}
// CanonicalTarNameForPath returns platform-specific filepath
// to canonical posix-style path for tar archival. p is relative
// path.
func CanonicalTarNameForPath(p string) string {
return filepath.ToSlash(p)
}
// chmodTarEntry is used to adjust the file permissions used in tar header based
// on the platform the archival is done.
func chmodTarEntry(perm os.FileMode) os.FileMode {
// perm &= 0755 // this 0-ed out tar flags (like link, regular file, directory marker etc.)
permPart := perm & os.ModePerm
noPermPart := perm &^ os.ModePerm
// Add the x bit: make everything +x from windows
permPart |= 0111
permPart &= 0755
// Remove group- and world-writable bits.
perm &= 0o755
return noPermPart | permPart
// Add the x bit: make everything +x on Windows
return perm | 0o111
}
func setHeaderForSpecialDevice(hdr *tar.Header, name string, stat interface{}) (err error) {
+1 -1
View File
@@ -41,7 +41,7 @@ func collectFileInfoForChanges(oldDir, newDir string) (*FileInfo, *FileInfo, err
func collectFileInfo(sourceDir string) (*FileInfo, error) {
root := newRootFileInfo()
err := filepath.Walk(sourceDir, func(path string, f os.FileInfo, err error) error {
err := filepath.WalkDir(sourceDir, func(path string, _ os.DirEntry, err error) error {
if err != nil {
return err
}
+18 -18
View File
@@ -26,23 +26,23 @@ var (
// path (from before being processed by utility functions from the path or
// filepath stdlib packages) ends with a trailing `/.` or `/`. If the cleaned
// path already ends in a `.` path segment, then another is not added. If the
// clean path already ends in the separator, then another is not added.
func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string, sep byte) string {
// clean path already ends in a path separator, then another is not added.
func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string) string {
// Ensure paths are in platform semantics
cleanedPath = strings.ReplaceAll(cleanedPath, "/", string(sep))
originalPath = strings.ReplaceAll(originalPath, "/", string(sep))
cleanedPath = normalizePath(cleanedPath)
originalPath = normalizePath(originalPath)
if !specifiesCurrentDir(cleanedPath) && specifiesCurrentDir(originalPath) {
if !hasTrailingPathSeparator(cleanedPath, sep) {
if !hasTrailingPathSeparator(cleanedPath) {
// Add a separator if it doesn't already end with one (a cleaned
// path would only end in a separator if it is the root).
cleanedPath += string(sep)
cleanedPath += string(filepath.Separator)
}
cleanedPath += "."
}
if !hasTrailingPathSeparator(cleanedPath, sep) && hasTrailingPathSeparator(originalPath, sep) {
cleanedPath += string(sep)
if !hasTrailingPathSeparator(cleanedPath) && hasTrailingPathSeparator(originalPath) {
cleanedPath += string(filepath.Separator)
}
return cleanedPath
@@ -51,14 +51,14 @@ func PreserveTrailingDotOrSeparator(cleanedPath string, originalPath string, sep
// assertsDirectory returns whether the given path is
// asserted to be a directory, i.e., the path ends with
// a trailing '/' or `/.`, assuming a path separator of `/`.
func assertsDirectory(path string, sep byte) bool {
return hasTrailingPathSeparator(path, sep) || specifiesCurrentDir(path)
func assertsDirectory(path string) bool {
return hasTrailingPathSeparator(path) || specifiesCurrentDir(path)
}
// hasTrailingPathSeparator returns whether the given
// path ends with the system's path separator character.
func hasTrailingPathSeparator(path string, sep byte) bool {
return len(path) > 0 && path[len(path)-1] == sep
func hasTrailingPathSeparator(path string) bool {
return len(path) > 0 && path[len(path)-1] == filepath.Separator
}
// specifiesCurrentDir returns whether the given path specifies
@@ -285,7 +285,7 @@ func PrepareArchiveCopy(srcContent io.Reader, srcInfo, dstInfo CopyInfo) (dstDir
srcBase = srcInfo.RebaseName
}
return dstDir, RebaseArchiveEntries(srcContent, srcBase, dstBase), nil
case assertsDirectory(dstInfo.Path, os.PathSeparator):
case assertsDirectory(dstInfo.Path):
// The destination does not exist and is asserted to be created as a
// directory, but the source content is not a directory. This is an
// error condition since you cannot create a directory from a file
@@ -386,8 +386,8 @@ func CopyResource(srcPath, dstPath string, followLink bool) error {
dstPath = normalizePath(dstPath)
// Clean the source and destination paths.
srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath, os.PathSeparator)
dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath, os.PathSeparator)
srcPath = PreserveTrailingDotOrSeparator(filepath.Clean(srcPath), srcPath)
dstPath = PreserveTrailingDotOrSeparator(filepath.Clean(dstPath), dstPath)
if srcInfo, err = CopyInfoSourcePath(srcPath, followLink); err != nil {
return err
@@ -450,7 +450,7 @@ func ResolveHostSourcePath(path string, followLink bool) (resolvedPath, rebaseNa
// resolvedDirPath will have been cleaned (no trailing path separators) so
// we can manually join it with the base path element.
resolvedPath = resolvedDirPath + string(filepath.Separator) + basePath
if hasTrailingPathSeparator(path, os.PathSeparator) &&
if hasTrailingPathSeparator(path) &&
filepath.Base(path) != filepath.Base(resolvedPath) {
rebaseName = filepath.Base(path)
}
@@ -469,8 +469,8 @@ func GetRebaseName(path, resolvedPath string) (string, string) {
resolvedPath += string(filepath.Separator) + "."
}
if hasTrailingPathSeparator(path, os.PathSeparator) &&
!hasTrailingPathSeparator(resolvedPath, os.PathSeparator) {
if hasTrailingPathSeparator(path) &&
!hasTrailingPathSeparator(resolvedPath) {
resolvedPath += string(filepath.Separator)
}
+22 -4
View File
@@ -87,7 +87,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
basename := filepath.Base(hdr.Name)
aufsHardlinks[basename] = hdr
if aufsTempdir == "" {
if aufsTempdir, err = os.MkdirTemp("", "dockerplnk"); err != nil {
if aufsTempdir, err = os.MkdirTemp(dest, "dockerplnk"); err != nil {
return 0, err
}
defer os.RemoveAll(aufsTempdir)
@@ -121,7 +121,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
if err != nil {
return 0, err
}
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
err = filepath.WalkDir(dir, func(path string, info os.DirEntry, err error) error {
if err != nil {
if os.IsNotExist(err) {
err = nil // parent was deleted
@@ -132,8 +132,7 @@ func UnpackLayer(dest string, layer io.Reader, options *TarOptions) (size int64,
return nil
}
if _, exists := unpackedPaths[path]; !exists {
err := os.RemoveAll(path)
return err
return os.RemoveAll(path)
}
return nil
})
@@ -224,6 +223,25 @@ func ApplyUncompressedLayer(dest string, layer io.Reader, options *TarOptions) (
return applyLayerHandler(dest, layer, options, false)
}
// IsEmpty checks if the tar archive is empty (doesn't contain any entries).
func IsEmpty(rd io.Reader) (bool, error) {
decompRd, err := DecompressStream(rd)
if err != nil {
return true, fmt.Errorf("failed to decompress archive: %v", err)
}
defer decompRd.Close()
tarReader := tar.NewReader(decompRd)
if _, err := tarReader.Next(); err != nil {
if err == io.EOF {
return true, nil
}
return false, fmt.Errorf("failed to read next archive header: %v", err)
}
return false, nil
}
// do the bulk load of ApplyLayer, but allow for not calling DecompressStream
func applyLayerHandler(dest string, layer io.Reader, options *TarOptions, decompress bool) (int64, error) {
dest = filepath.Clean(dest)
+20
View File
@@ -0,0 +1,20 @@
package archive
// CheckSystemDriveAndRemoveDriveLetter verifies that a path, if it includes a drive letter,
// is the system drive.
// On Linux: this is a no-op.
// On Windows: this does the following>
// CheckSystemDriveAndRemoveDriveLetter verifies and manipulates a Windows path.
// This is used, for example, when validating a user provided path in docker cp.
// If a drive letter is supplied, it must be the system drive. The drive letter
// is always removed. Also, it translates it to OS semantics (IOW / to \). We
// need the path in this syntax so that it can ultimately be concatenated with
// a Windows long-path which doesn't support drive-letters. Examples:
// C: --> Fail
// C:\ --> \
// a --> a
// /a --> \a
// d:\ --> Fail
func CheckSystemDriveAndRemoveDriveLetter(path string) (string, error) {
return checkSystemDriveAndRemoveDriveLetter(path)
}
+10
View File
@@ -0,0 +1,10 @@
//go:build !windows
// +build !windows
package archive
// checkSystemDriveAndRemoveDriveLetter is the non-Windows implementation
// of CheckSystemDriveAndRemoveDriveLetter
func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
return path, nil
}
+22
View File
@@ -0,0 +1,22 @@
package archive
import (
"fmt"
"path/filepath"
"strings"
)
// checkSystemDriveAndRemoveDriveLetter is the Windows implementation
// of CheckSystemDriveAndRemoveDriveLetter
func checkSystemDriveAndRemoveDriveLetter(path string) (string, error) {
if len(path) == 2 && string(path[1]) == ":" {
return "", fmt.Errorf("no relative path specified in %q", path)
}
if !filepath.IsAbs(path) || len(path) < 2 {
return filepath.FromSlash(path), nil
}
if string(path[1]) == ":" && !strings.EqualFold(string(path[0]), "c") {
return "", fmt.Errorf("the specified path is not on the system drive (C:)")
}
return filepath.FromSlash(path[2:]), nil
}
-44
View File
@@ -1,44 +0,0 @@
package fileutils
import "github.com/moby/patternmatcher"
type (
// PatternMatcher allows checking paths against a list of patterns.
//
// Deprecated: use github.com/moby/patternmatcher.PatternMatcher
PatternMatcher = patternmatcher.PatternMatcher
// MatchInfo tracks information about parent dir matches while traversing a
// filesystem.
//
// Deprecated: use github.com/moby/patternmatcher.MatchInfo
MatchInfo = patternmatcher.MatchInfo
// Pattern defines a single regexp used to filter file paths.
//
// Deprecated: use github.com/moby/patternmatcher.Pattern
Pattern = patternmatcher.Pattern
)
var (
// NewPatternMatcher creates a new matcher object for specific patterns that can
// be used later to match against patterns against paths
//
// Deprecated: use github.com/moby/patternmatcher.New
NewPatternMatcher = patternmatcher.New
// Matches returns true if file matches any of the patterns
// and isn't excluded by any of the subsequent patterns.
//
// This implementation is buggy (it only checks a single parent dir against the
// pattern) and will be removed soon. Use MatchesOrParentMatches instead.
//
// Deprecated: use github.com/moby/patternmatcher.Matches
Matches = patternmatcher.Matches
// MatchesOrParentMatches returns true if file matches any of the patterns
// and isn't excluded by any of the subsequent patterns.
//
// Deprecated: use github.com/moby/patternmatcher.MatchesOrParentMatches
MatchesOrParentMatches = patternmatcher.MatchesOrParentMatches
)
-74
View File
@@ -1,74 +0,0 @@
package fileutils // import "github.com/docker/docker/pkg/fileutils"
import (
"fmt"
"io"
"os"
"path/filepath"
)
// CopyFile copies from src to dst until either EOF is reached
// on src or an error occurs. It verifies src exists and removes
// the dst if it exists.
func CopyFile(src, dst string) (int64, error) {
cleanSrc := filepath.Clean(src)
cleanDst := filepath.Clean(dst)
if cleanSrc == cleanDst {
return 0, nil
}
sf, err := os.Open(cleanSrc)
if err != nil {
return 0, err
}
defer sf.Close()
if err := os.Remove(cleanDst); err != nil && !os.IsNotExist(err) {
return 0, err
}
df, err := os.Create(cleanDst)
if err != nil {
return 0, err
}
defer df.Close()
return io.Copy(df, sf)
}
// ReadSymlinkedDirectory returns the target directory of a symlink.
// The target of the symbolic link may not be a file.
func ReadSymlinkedDirectory(path string) (string, error) {
var realPath string
var err error
if realPath, err = filepath.Abs(path); err != nil {
return "", fmt.Errorf("unable to get absolute path for %s: %s", path, err)
}
if realPath, err = filepath.EvalSymlinks(realPath); err != nil {
return "", fmt.Errorf("failed to canonicalise path for %s: %s", path, err)
}
realPathInfo, err := os.Stat(realPath)
if err != nil {
return "", fmt.Errorf("failed to stat target '%s' of '%s': %s", realPath, path, err)
}
if !realPathInfo.Mode().IsDir() {
return "", fmt.Errorf("canonical path points to a file '%s'", realPath)
}
return realPath, nil
}
// CreateIfNotExists creates a file or a directory only if it does not already exist.
func CreateIfNotExists(path string, isDir bool) error {
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
if isDir {
return os.MkdirAll(path, 0755)
}
if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
return err
}
f, err := os.OpenFile(path, os.O_CREATE, 0755)
if err != nil {
return err
}
f.Close()
}
}
return nil
}
-27
View File
@@ -1,27 +0,0 @@
package fileutils // import "github.com/docker/docker/pkg/fileutils"
import (
"os"
"os/exec"
"strconv"
"strings"
)
// GetTotalUsedFds returns the number of used File Descriptors by
// executing `lsof -p PID`
func GetTotalUsedFds() int {
pid := os.Getpid()
cmd := exec.Command("lsof", "-p", strconv.Itoa(pid))
output, err := cmd.CombinedOutput()
if err != nil {
return -1
}
outputStr := strings.TrimSpace(string(output))
fds := strings.Split(outputStr, "\n")
return len(fds) - 1
}
-22
View File
@@ -1,22 +0,0 @@
//go:build linux || freebsd
// +build linux freebsd
package fileutils // import "github.com/docker/docker/pkg/fileutils"
import (
"fmt"
"os"
"github.com/sirupsen/logrus"
)
// GetTotalUsedFds Returns the number of used File Descriptors by
// reading it via /proc filesystem.
func GetTotalUsedFds() int {
if fds, err := os.ReadDir(fmt.Sprintf("/proc/%d/fd", os.Getpid())); err != nil {
logrus.Errorf("Error opening /proc/%d/fd: %s", os.Getpid(), err)
} else {
return len(fds)
}
return -1
}
-7
View File
@@ -1,7 +0,0 @@
package fileutils // import "github.com/docker/docker/pkg/fileutils"
// GetTotalUsedFds Returns the number of used File Descriptors. Not supported
// on Windows.
func GetTotalUsedFds() int {
return -1
}
+6 -3
View File
@@ -64,13 +64,14 @@ func stick(f string) error {
// GetDataHome returns XDG_DATA_HOME.
// GetDataHome returns $HOME/.local/share and nil error if XDG_DATA_HOME is not set.
// If HOME and XDG_DATA_HOME are not set, getpwent(3) is consulted to determine the users home directory.
//
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
func GetDataHome() (string, error) {
if xdgDataHome := os.Getenv("XDG_DATA_HOME"); xdgDataHome != "" {
return xdgDataHome, nil
}
home := os.Getenv("HOME")
home := Get()
if home == "" {
return "", errors.New("could not get either XDG_DATA_HOME or HOME")
}
@@ -79,13 +80,14 @@ func GetDataHome() (string, error) {
// GetConfigHome returns XDG_CONFIG_HOME.
// GetConfigHome returns $HOME/.config and nil error if XDG_CONFIG_HOME is not set.
// If HOME and XDG_CONFIG_HOME are not set, getpwent(3) is consulted to determine the users home directory.
//
// See also https://standards.freedesktop.org/basedir-spec/latest/ar01s03.html
func GetConfigHome() (string, error) {
if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
return xdgConfigHome, nil
}
home := os.Getenv("HOME")
home := Get()
if home == "" {
return "", errors.New("could not get either XDG_CONFIG_HOME or HOME")
}
@@ -93,8 +95,9 @@ func GetConfigHome() (string, error) {
}
// GetLibHome returns $HOME/.local/lib
// If HOME is not set, getpwent(3) is consulted to determine the users home directory.
func GetLibHome() (string, error) {
home := os.Getenv("HOME")
home := Get()
if home == "" {
return "", errors.New("could not get HOME")
}
-14
View File
@@ -162,20 +162,6 @@ func (i IdentityMapping) Empty() bool {
return len(i.UIDMaps) == 0 && len(i.GIDMaps) == 0
}
// UIDs returns the mapping for UID.
//
// Deprecated: reference the UIDMaps field directly.
func (i IdentityMapping) UIDs() []IDMap {
return i.UIDMaps
}
// GIDs returns the mapping for GID.
//
// Deprecated: reference the GIDMaps field directly.
func (i IdentityMapping) GIDs() []IDMap {
return i.GIDMaps
}
func createIDMap(subidRanges ranges) []IDMap {
idMap := []IDMap{}
+26 -66
View File
@@ -14,9 +14,7 @@ import (
"sync"
"syscall"
"github.com/docker/docker/pkg/system"
"github.com/opencontainers/runc/libcontainer/user"
"github.com/pkg/errors"
)
var (
@@ -25,18 +23,12 @@ var (
)
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
// make an array containing the original path asked for, plus (for mkAll == true)
// all path components leading up to the complete path that don't exist before we MkdirAll
// so that we can chown all of them properly at the end. If chownExisting is false, we won't
// chown the full directory path if it exists
var paths []string
path, err := filepath.Abs(path)
if err != nil {
return err
}
stat, err := system.Stat(path)
stat, err := os.Stat(path)
if err == nil {
if !stat.IsDir() {
return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
@@ -45,10 +37,15 @@ func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting
return nil
}
// short-circuit--we were called with an existing directory and chown was requested
return setPermissions(path, mode, owner.UID, owner.GID, stat)
// short-circuit -- we were called with an existing directory and chown was requested
return setPermissions(path, mode, owner, stat)
}
// make an array containing the original path asked for, plus (for mkAll == true)
// all path components leading up to the complete path that don't exist before we MkdirAll
// so that we can chown all of them properly at the end. If chownExisting is false, we won't
// chown the full directory path if it exists
var paths []string
if os.IsNotExist(err) {
paths = []string{path}
}
@@ -62,54 +59,26 @@ func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting
if dirPath == "/" {
break
}
if _, err := os.Stat(dirPath); err != nil && os.IsNotExist(err) {
if _, err = os.Stat(dirPath); err != nil && os.IsNotExist(err) {
paths = append(paths, dirPath)
}
}
if err := system.MkdirAll(path, mode); err != nil {
return err
}
} else {
if err := os.Mkdir(path, mode); err != nil && !os.IsExist(err) {
if err = os.MkdirAll(path, mode); err != nil {
return err
}
} else if err = os.Mkdir(path, mode); err != nil {
return err
}
// even if it existed, we will chown the requested path + any subpaths that
// didn't exist when we called MkdirAll
for _, pathComponent := range paths {
if err := setPermissions(pathComponent, mode, owner.UID, owner.GID, nil); err != nil {
if err = setPermissions(pathComponent, mode, owner, nil); err != nil {
return err
}
}
return nil
}
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
// if that uid, gid pair has access (execute bit) to the directory
func CanAccess(path string, pair Identity) bool {
statInfo, err := system.Stat(path)
if err != nil {
return false
}
fileMode := os.FileMode(statInfo.Mode())
permBits := fileMode.Perm()
return accessible(statInfo.UID() == uint32(pair.UID),
statInfo.GID() == uint32(pair.GID), permBits)
}
func accessible(isOwner, isGroup bool, perms os.FileMode) bool {
if isOwner && (perms&0100 == 0100) {
return true
}
if isGroup && (perms&0010 == 0010) {
return true
}
if perms&0001 == 0001 {
return true
}
return false
}
// LookupUser uses traditional local system files lookup (from libcontainer/user) on a username,
// followed by a call to `getent` for supporting host configured non-files passwd and group dbs
func LookupUser(name string) (user.User, error) {
@@ -198,7 +167,10 @@ func callGetent(database, key string) (io.Reader, error) {
if getentCmd == "" {
return nil, fmt.Errorf("unable to find getent command")
}
out, err := execCmd(getentCmd, database, key)
command := exec.Command(getentCmd, database, key)
// we run getent within container filesystem, but without /dev so /dev/null is not available for exec to mock stdin
command.Stdin = io.NopCloser(bytes.NewReader(nil))
out, err := command.CombinedOutput()
if err != nil {
exitCode, errC := getExitCode(err)
if errC != nil {
@@ -234,36 +206,24 @@ func getExitCode(err error) (int, error) {
// Normally a Chown is a no-op if uid/gid match, but in some cases this can still cause an error, e.g. if the
// dir is on an NFS share, so don't call chown unless we absolutely must.
// Likewise for setting permissions.
func setPermissions(p string, mode os.FileMode, uid, gid int, stat *system.StatT) error {
func setPermissions(p string, mode os.FileMode, owner Identity, stat os.FileInfo) error {
if stat == nil {
var err error
stat, err = system.Stat(p)
stat, err = os.Stat(p)
if err != nil {
return err
}
}
if os.FileMode(stat.Mode()).Perm() != mode.Perm() {
if stat.Mode().Perm() != mode.Perm() {
if err := os.Chmod(p, mode.Perm()); err != nil {
return err
}
}
if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) {
ssi := stat.Sys().(*syscall.Stat_t)
if ssi.Uid == uint32(owner.UID) && ssi.Gid == uint32(owner.GID) {
return nil
}
return os.Chown(p, uid, gid)
}
// NewIdentityMapping takes a requested username and
// using the data from /etc/sub{uid,gid} ranges, creates the
// proper uid and gid remapping ranges for that user/group pair
//
// Deprecated: Use LoadIdentityMapping.
func NewIdentityMapping(name string) (*IdentityMapping, error) {
m, err := LoadIdentityMapping(name)
if err != nil {
return nil, err
}
return &m, err
return os.Chown(p, owner.UID, owner.GID)
}
// LoadIdentityMapping takes a requested username and
@@ -272,7 +232,7 @@ func NewIdentityMapping(name string) (*IdentityMapping, error) {
func LoadIdentityMapping(name string) (IdentityMapping, error) {
usr, err := LookupUser(name)
if err != nil {
return IdentityMapping{}, fmt.Errorf("Could not get user for username %s: %v", name, err)
return IdentityMapping{}, fmt.Errorf("could not get user for username %s: %v", name, err)
}
subuidRanges, err := lookupSubUIDRanges(usr)
@@ -302,7 +262,7 @@ func lookupSubUIDRanges(usr user.User) ([]IDMap, error) {
}
}
if len(rangeList) == 0 {
return nil, errors.Errorf("no subuid ranges found for user %q", usr.Name)
return nil, fmt.Errorf("no subuid ranges found for user %q", usr.Name)
}
return createIDMap(rangeList), nil
}
@@ -319,7 +279,7 @@ func lookupSubGIDRanges(usr user.User) ([]IDMap, error) {
}
}
if len(rangeList) == 0 {
return nil, errors.Errorf("no subgid ranges found for user %q", usr.Name)
return nil, fmt.Errorf("no subgid ranges found for user %q", usr.Name)
}
return createIDMap(rangeList), nil
}
+2 -12
View File
@@ -19,16 +19,6 @@ const (
// permissions aren't set through this path, the identity isn't utilized.
// Ownership is handled elsewhere, but in the future could be support here
// too.
func mkdirAs(path string, mode os.FileMode, owner Identity, mkAll, chownExisting bool) error {
if err := system.MkdirAll(path, mode); err != nil {
return err
}
return nil
}
// CanAccess takes a valid (existing) directory and a uid, gid pair and determines
// if that uid, gid pair has access (execute bit) to the directory
// Windows does not require/support this function, so always return true
func CanAccess(path string, identity Identity) bool {
return true
func mkdirAs(path string, _ os.FileMode, _ Identity, _, _ bool) error {
return system.MkdirAll(path, 0)
}
+20 -17
View File
@@ -2,6 +2,7 @@ package idtools // import "github.com/docker/docker/pkg/idtools"
import (
"fmt"
"os/exec"
"regexp"
"sort"
"strconv"
@@ -32,21 +33,21 @@ const (
// mapping ranges in containers.
func AddNamespaceRangesUser(name string) (int, int, error) {
if err := addUser(name); err != nil {
return -1, -1, fmt.Errorf("Error adding user %q: %v", name, err)
return -1, -1, fmt.Errorf("error adding user %q: %v", name, err)
}
// Query the system for the created uid and gid pair
out, err := execCmd("id", name)
out, err := exec.Command("id", name).CombinedOutput()
if err != nil {
return -1, -1, fmt.Errorf("Error trying to find uid/gid for new user %q: %v", name, err)
return -1, -1, fmt.Errorf("error trying to find uid/gid for new user %q: %v", name, err)
}
matches := idOutRegexp.FindStringSubmatch(strings.TrimSpace(string(out)))
if len(matches) != 3 {
return -1, -1, fmt.Errorf("Can't find uid, gid from `id` output: %q", string(out))
return -1, -1, fmt.Errorf("can't find uid, gid from `id` output: %q", string(out))
}
uid, err := strconv.Atoi(matches[1])
if err != nil {
return -1, -1, fmt.Errorf("Can't convert found uid (%s) to int: %v", matches[1], err)
return -1, -1, fmt.Errorf("can't convert found uid (%s) to int: %v", matches[1], err)
}
gid, err := strconv.Atoi(matches[2])
if err != nil {
@@ -57,7 +58,7 @@ func AddNamespaceRangesUser(name string) (int, int, error) {
// do not get auto-created ranges in subuid/subgid)
if err := createSubordinateRanges(name); err != nil {
return -1, -1, fmt.Errorf("Couldn't create subordinate ID ranges: %v", err)
return -1, -1, fmt.Errorf("couldn't create subordinate ID ranges: %v", err)
}
return uid, gid, nil
}
@@ -81,7 +82,7 @@ func addUser(name string) error {
return fmt.Errorf("cannot add user; no useradd/adduser binary found")
}
if out, err := execCmd(userCommand, args...); err != nil {
if out, err := exec.Command(userCommand, args...).CombinedOutput(); err != nil {
return fmt.Errorf("failed to add user with error: %v; output: %q", err, string(out))
}
return nil
@@ -92,33 +93,35 @@ func createSubordinateRanges(name string) error {
// by the distro tooling
ranges, err := parseSubuid(name)
if err != nil {
return fmt.Errorf("Error while looking for subuid ranges for user %q: %v", name, err)
return fmt.Errorf("error while looking for subuid ranges for user %q: %v", name, err)
}
if len(ranges) == 0 {
// no UID ranges; let's create one
startID, err := findNextUIDRange()
if err != nil {
return fmt.Errorf("Can't find available subuid range: %v", err)
return fmt.Errorf("can't find available subuid range: %v", err)
}
out, err := execCmd("usermod", "-v", fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1), name)
idRange := fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1)
out, err := exec.Command("usermod", "-v", idRange, name).CombinedOutput()
if err != nil {
return fmt.Errorf("Unable to add subuid range to user: %q; output: %s, err: %v", name, out, err)
return fmt.Errorf("unable to add subuid range to user: %q; output: %s, err: %v", name, out, err)
}
}
ranges, err = parseSubgid(name)
if err != nil {
return fmt.Errorf("Error while looking for subgid ranges for user %q: %v", name, err)
return fmt.Errorf("error while looking for subgid ranges for user %q: %v", name, err)
}
if len(ranges) == 0 {
// no GID ranges; let's create one
startID, err := findNextGIDRange()
if err != nil {
return fmt.Errorf("Can't find available subgid range: %v", err)
return fmt.Errorf("can't find available subgid range: %v", err)
}
out, err := execCmd("usermod", "-w", fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1), name)
idRange := fmt.Sprintf("%d-%d", startID, startID+defaultRangeLen-1)
out, err := exec.Command("usermod", "-w", idRange, name).CombinedOutput()
if err != nil {
return fmt.Errorf("Unable to add subgid range to user: %q; output: %s, err: %v", name, out, err)
return fmt.Errorf("unable to add subgid range to user: %q; output: %s, err: %v", name, out, err)
}
}
return nil
@@ -127,7 +130,7 @@ func createSubordinateRanges(name string) error {
func findNextUIDRange() (int, error) {
ranges, err := parseSubuid("ALL")
if err != nil {
return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subuid file: %v", err)
return -1, fmt.Errorf("couldn't parse all ranges in /etc/subuid file: %v", err)
}
sort.Sort(ranges)
return findNextRangeStart(ranges)
@@ -136,7 +139,7 @@ func findNextUIDRange() (int, error) {
func findNextGIDRange() (int, error) {
ranges, err := parseSubgid("ALL")
if err != nil {
return -1, fmt.Errorf("Couldn't parse all ranges in /etc/subgid file: %v", err)
return -1, fmt.Errorf("couldn't parse all ranges in /etc/subgid file: %v", err)
}
sort.Sort(ranges)
return findNextRangeStart(ranges)
-5
View File
@@ -25,8 +25,3 @@ func resolveBinary(binname string) (string, error) {
}
return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath)
}
func execCmd(cmd string, arg ...string) ([]byte, error) {
execCmd := exec.Command(cmd, arg...)
return execCmd.CombinedOutput()
}
-11
View File
@@ -1,11 +0,0 @@
//go:build !windows
// +build !windows
package ioutils // import "github.com/docker/docker/pkg/ioutils"
import "os"
// TempDir on Unix systems is equivalent to os.MkdirTemp.
func TempDir(dir, prefix string) (string, error) {
return os.MkdirTemp(dir, prefix)
}
-16
View File
@@ -1,16 +0,0 @@
package ioutils // import "github.com/docker/docker/pkg/ioutils"
import (
"os"
"github.com/docker/docker/pkg/longpath"
)
// TempDir is the equivalent of os.MkdirTemp, except that the result is in Windows longpath format.
func TempDir(dir, prefix string) (string, error) {
tempDir, err := os.MkdirTemp(dir, prefix)
if err != nil {
return "", err
}
return longpath.AddPrefix(tempDir), nil
}
+10
View File
@@ -0,0 +1,10 @@
package ioutils
import "github.com/docker/docker/pkg/longpath"
// TempDir is the equivalent of [os.MkdirTemp], except that on Windows
// the result is in Windows longpath format. On Unix systems it is
// equivalent to [os.MkdirTemp].
//
// Deprecated: use [longpath.MkdirTemp].
var TempDir = longpath.MkdirTemp
Loaded 100 of 368 files, more files were not shown because too many files have changed in this diff. Show more