mirror of
https://github.com/k3s-io/k3s.git
synced 2024-06-07 19:41:36 +00:00
Bump rootlesskit
This commit is contained in:
parent
782004bec9
commit
8c9ed8e197
4
go.mod
4
go.mod
@ -82,7 +82,6 @@ require (
|
||||
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 // indirect
|
||||
github.com/go-bindata/go-bindata v3.1.2+incompatible
|
||||
github.com/go-sql-driver/mysql v1.4.1
|
||||
github.com/gofrs/flock v0.7.1 // indirect
|
||||
github.com/gogo/googleapis v1.3.0 // indirect
|
||||
github.com/google/tcpproxy v0.0.0-20180808230851-dfa16c61dad2
|
||||
github.com/gorilla/mux v1.7.3
|
||||
@ -103,11 +102,10 @@ require (
|
||||
github.com/rancher/remotedialer v0.2.0
|
||||
github.com/rancher/wrangler v0.4.0
|
||||
github.com/rancher/wrangler-api v0.4.0
|
||||
github.com/rootless-containers/rootlesskit v0.6.0
|
||||
github.com/rootless-containers/rootlesskit v0.7.2
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/tchap/go-patricia v2.3.0+incompatible // indirect
|
||||
github.com/theckman/go-flock v0.7.1 // indirect
|
||||
github.com/urfave/cli v1.22.2
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
||||
golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a
|
||||
|
18
go.sum
18
go.sum
@ -113,7 +113,6 @@ github.com/buger/jsonparser v0.0.0-20180808090653-f4dd9f5a6b44/go.mod h1:bbYlZJ7
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1/qq+pCNd3VZOAEI9jy6Bi131YlXgI=
|
||||
github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s=
|
||||
github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
|
||||
github.com/canonical/go-dqlite v1.2.0 h1:TCsNV/mAmPy7PQa4jIQMoiXbCUVqYTSv6OJSpi/qdX8=
|
||||
github.com/canonical/go-dqlite v1.2.0/go.mod h1:wp00vfMvPYgNCyxcPdHB5XExmDoCGoPUGymloAQT17Y=
|
||||
github.com/canonical/go-dqlite v1.3.0 h1:c+7eGZfh0K7yCmGrBkNRGZdY8R8+2jSSkz6Zr3YCjJE=
|
||||
github.com/canonical/go-dqlite v1.3.0/go.mod h1:wp00vfMvPYgNCyxcPdHB5XExmDoCGoPUGymloAQT17Y=
|
||||
@ -490,7 +489,9 @@ github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
|
||||
github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/insomniacslk/dhcp v0.0.0-20190712084813-dc1a53400564/go.mod h1:CfMdguCK66I5DAUJgGKyNz8aB6vO5dZzkm9Xep6WGvw=
|
||||
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
|
||||
github.com/jamescun/tuntap v0.0.0-20190712092105-cb1fb277045c/go.mod h1:zzwpsgcYhzzIP5WyF8g9ivCv38cY9uAV9Gu0m3lThhE=
|
||||
github.com/jefferai/jsonx v1.0.0/go.mod h1:OGmqmi2tTeI/PS+qQfBDToLHHJIy/RMp24fPo8vFvoQ=
|
||||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU=
|
||||
github.com/jetstack/cert-manager v0.7.2/go.mod h1:nbddmhjWxYGt04bxvwVGUSeLhZ2PCyNvd7MpXdq+yWY=
|
||||
@ -615,6 +616,7 @@ github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:F
|
||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/moby/vpnkit v0.3.1-0.20190720080441-7dd3dcce7d3d/go.mod h1:KyjUrL9cb6ZSNNAUwZfqRjhwwgJ3BJN+kXh0t43WTUQ=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@ -649,7 +651,6 @@ github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
||||
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
@ -658,7 +659,6 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
@ -781,8 +781,8 @@ github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfm
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rootless-containers/rootlesskit v0.6.0 h1:L7DxVAlaNhg4M/+i2GCl24kRkXO5q81C/lu4jlMz3bE=
|
||||
github.com/rootless-containers/rootlesskit v0.6.0/go.mod h1:HO7iU3+dH2N6yQL4DcUGQpzVZ7e7VYWNdtTAOR/P3FM=
|
||||
github.com/rootless-containers/rootlesskit v0.7.2 h1:gcWQ9/GN98ne1AqnoeOgQ8e6qpKd3BuB4ug+2h95Fr0=
|
||||
github.com/rootless-containers/rootlesskit v0.7.2/go.mod h1:r9YL5mKRIdnwcYk4G8E5CSc9MDeFtgYmhfE4CSvDGYA=
|
||||
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c h1:ht7N4d/B7Ezf58nvMNVF3OlvDlz9pp+WHVcRNS0nink=
|
||||
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
|
||||
github.com/russross/blackfriday v0.0.0-20170610170232-067529f716f4/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
@ -862,6 +862,7 @@ github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhV
|
||||
github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8 h1:ndzgwNDnKIqyCvHTXaCqh9KlOWKvBry6nuXMJmonVsE=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/u-root/u-root v5.0.0+incompatible/go.mod h1:RYkpo8pTHrNjW08opNd/U6p/RJE7K0D8fXO0d47+3YY=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ultraware/funlen v0.0.1/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA=
|
||||
@ -969,11 +970,11 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI=
|
||||
golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a h1:+HHJiFUXVOIS9mr1ThqkQD1N8vpFCfCShqADBM12KTc=
|
||||
golang.org/x/net v0.0.0-20191204025024-5ee1b9f4859a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
@ -1016,11 +1017,11 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e h1:9vRrk9YW2BTzLP0VCB9ZDjU4cPqkg+IDWL7XgxA1yxQ=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@ -1094,7 +1095,6 @@ google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRn
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64 h1:iKtrH9Y8mcbADOP0YFaEMth7OfuHY9xHOwNj4znpM1A=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
@ -1107,7 +1107,6 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
|
||||
google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
|
||||
google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
@ -1145,7 +1144,6 @@ gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRN
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
231
vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go
generated
vendored
231
vendor/github.com/docker/docker/pkg/idtools/idtools_unix.go
generated
vendored
@ -1,231 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package idtools // import "github.com/docker/docker/pkg/idtools"
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/pkg/system"
|
||||
"github.com/opencontainers/runc/libcontainer/user"
|
||||
)
|
||||
|
||||
var (
|
||||
entOnce sync.Once
|
||||
getentCmd string
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
stat, err := system.Stat(path)
|
||||
if err == nil {
|
||||
if !stat.IsDir() {
|
||||
return &os.PathError{Op: "mkdir", Path: path, Err: syscall.ENOTDIR}
|
||||
}
|
||||
if !chownExisting {
|
||||
return nil
|
||||
}
|
||||
|
||||
// short-circuit--we were called with an existing directory and chown was requested
|
||||
return lazyChown(path, owner.UID, owner.GID, stat)
|
||||
}
|
||||
|
||||
if os.IsNotExist(err) {
|
||||
paths = []string{path}
|
||||
}
|
||||
|
||||
if mkAll {
|
||||
// walk back to "/" looking for directories which do not exist
|
||||
// and add them to the paths array for chown after creation
|
||||
dirPath := path
|
||||
for {
|
||||
dirPath = filepath.Dir(dirPath)
|
||||
if dirPath == "/" {
|
||||
break
|
||||
}
|
||||
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) {
|
||||
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 := lazyChown(pathComponent, owner.UID, owner.GID, 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(username string) (user.User, error) {
|
||||
// first try a local system files lookup using existing capabilities
|
||||
usr, err := user.LookupUser(username)
|
||||
if err == nil {
|
||||
return usr, nil
|
||||
}
|
||||
// local files lookup failed; attempt to call `getent` to query configured passwd dbs
|
||||
usr, err = getentUser(fmt.Sprintf("%s %s", "passwd", username))
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
return usr, nil
|
||||
}
|
||||
|
||||
// LookupUID uses traditional local system files lookup (from libcontainer/user) on a uid,
|
||||
// followed by a call to `getent` for supporting host configured non-files passwd and group dbs
|
||||
func LookupUID(uid int) (user.User, error) {
|
||||
// first try a local system files lookup using existing capabilities
|
||||
usr, err := user.LookupUid(uid)
|
||||
if err == nil {
|
||||
return usr, nil
|
||||
}
|
||||
// local files lookup failed; attempt to call `getent` to query configured passwd dbs
|
||||
return getentUser(fmt.Sprintf("%s %d", "passwd", uid))
|
||||
}
|
||||
|
||||
func getentUser(args string) (user.User, error) {
|
||||
reader, err := callGetent(args)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
users, err := user.ParsePasswd(reader)
|
||||
if err != nil {
|
||||
return user.User{}, err
|
||||
}
|
||||
if len(users) == 0 {
|
||||
return user.User{}, fmt.Errorf("getent failed to find passwd entry for %q", strings.Split(args, " ")[1])
|
||||
}
|
||||
return users[0], nil
|
||||
}
|
||||
|
||||
// LookupGroup uses traditional local system files lookup (from libcontainer/user) on a group name,
|
||||
// followed by a call to `getent` for supporting host configured non-files passwd and group dbs
|
||||
func LookupGroup(groupname string) (user.Group, error) {
|
||||
// first try a local system files lookup using existing capabilities
|
||||
group, err := user.LookupGroup(groupname)
|
||||
if err == nil {
|
||||
return group, nil
|
||||
}
|
||||
// local files lookup failed; attempt to call `getent` to query configured group dbs
|
||||
return getentGroup(fmt.Sprintf("%s %s", "group", groupname))
|
||||
}
|
||||
|
||||
// LookupGID uses traditional local system files lookup (from libcontainer/user) on a group ID,
|
||||
// followed by a call to `getent` for supporting host configured non-files passwd and group dbs
|
||||
func LookupGID(gid int) (user.Group, error) {
|
||||
// first try a local system files lookup using existing capabilities
|
||||
group, err := user.LookupGid(gid)
|
||||
if err == nil {
|
||||
return group, nil
|
||||
}
|
||||
// local files lookup failed; attempt to call `getent` to query configured group dbs
|
||||
return getentGroup(fmt.Sprintf("%s %d", "group", gid))
|
||||
}
|
||||
|
||||
func getentGroup(args string) (user.Group, error) {
|
||||
reader, err := callGetent(args)
|
||||
if err != nil {
|
||||
return user.Group{}, err
|
||||
}
|
||||
groups, err := user.ParseGroup(reader)
|
||||
if err != nil {
|
||||
return user.Group{}, err
|
||||
}
|
||||
if len(groups) == 0 {
|
||||
return user.Group{}, fmt.Errorf("getent failed to find groups entry for %q", strings.Split(args, " ")[1])
|
||||
}
|
||||
return groups[0], nil
|
||||
}
|
||||
|
||||
func callGetent(args string) (io.Reader, error) {
|
||||
entOnce.Do(func() { getentCmd, _ = resolveBinary("getent") })
|
||||
// if no `getent` command on host, can't do anything else
|
||||
if getentCmd == "" {
|
||||
return nil, fmt.Errorf("")
|
||||
}
|
||||
out, err := execCmd(getentCmd, args)
|
||||
if err != nil {
|
||||
exitCode, errC := system.GetExitCode(err)
|
||||
if errC != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch exitCode {
|
||||
case 1:
|
||||
return nil, fmt.Errorf("getent reported invalid parameters/database unknown")
|
||||
case 2:
|
||||
terms := strings.Split(args, " ")
|
||||
return nil, fmt.Errorf("getent unable to find entry %q in %s database", terms[1], terms[0])
|
||||
case 3:
|
||||
return nil, fmt.Errorf("getent database doesn't support enumeration")
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
}
|
||||
return bytes.NewReader(out), nil
|
||||
}
|
||||
|
||||
// lazyChown performs a chown only if the uid/gid don't match what's requested
|
||||
// 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.
|
||||
func lazyChown(p string, uid, gid int, stat *system.StatT) error {
|
||||
if stat == nil {
|
||||
var err error
|
||||
stat, err = system.Stat(p)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if stat.UID() == uint32(uid) && stat.GID() == uint32(gid) {
|
||||
return nil
|
||||
}
|
||||
return os.Chown(p, uid, gid)
|
||||
}
|
25
vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go
generated
vendored
25
vendor/github.com/docker/docker/pkg/idtools/idtools_windows.go
generated
vendored
@ -1,25 +0,0 @@
|
||||
package idtools // import "github.com/docker/docker/pkg/idtools"
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/docker/docker/pkg/system"
|
||||
)
|
||||
|
||||
// This is currently a wrapper around MkdirAll, however, since currently
|
||||
// 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
|
||||
}
|
164
vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go
generated
vendored
164
vendor/github.com/docker/docker/pkg/idtools/usergroupadd_linux.go
generated
vendored
@ -1,164 +0,0 @@
|
||||
package idtools // import "github.com/docker/docker/pkg/idtools"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// add a user and/or group to Linux /etc/passwd, /etc/group using standard
|
||||
// Linux distribution commands:
|
||||
// adduser --system --shell /bin/false --disabled-login --disabled-password --no-create-home --group <username>
|
||||
// useradd -r -s /bin/false <username>
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
userCommand string
|
||||
|
||||
cmdTemplates = map[string]string{
|
||||
"adduser": "--system --shell /bin/false --no-create-home --disabled-login --disabled-password --group %s",
|
||||
"useradd": "-r -s /bin/false %s",
|
||||
"usermod": "-%s %d-%d %s",
|
||||
}
|
||||
|
||||
idOutRegexp = regexp.MustCompile(`uid=([0-9]+).*gid=([0-9]+)`)
|
||||
// default length for a UID/GID subordinate range
|
||||
defaultRangeLen = 65536
|
||||
defaultRangeStart = 100000
|
||||
userMod = "usermod"
|
||||
)
|
||||
|
||||
// AddNamespaceRangesUser takes a username and uses the standard system
|
||||
// utility to create a system user/group pair used to hold the
|
||||
// /etc/sub{uid,gid} ranges which will be used for user namespace
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Query the system for the created uid and gid pair
|
||||
out, err := execCmd("id", name)
|
||||
if err != nil {
|
||||
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))
|
||||
}
|
||||
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)
|
||||
}
|
||||
gid, err := strconv.Atoi(matches[2])
|
||||
if err != nil {
|
||||
return -1, -1, fmt.Errorf("Can't convert found gid (%s) to int: %v", matches[2], err)
|
||||
}
|
||||
|
||||
// Now we need to create the subuid/subgid ranges for our new user/group (system users
|
||||
// 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 uid, gid, nil
|
||||
}
|
||||
|
||||
func addUser(userName string) error {
|
||||
once.Do(func() {
|
||||
// set up which commands are used for adding users/groups dependent on distro
|
||||
if _, err := resolveBinary("adduser"); err == nil {
|
||||
userCommand = "adduser"
|
||||
} else if _, err := resolveBinary("useradd"); err == nil {
|
||||
userCommand = "useradd"
|
||||
}
|
||||
})
|
||||
if userCommand == "" {
|
||||
return fmt.Errorf("Cannot add user; no useradd/adduser binary found")
|
||||
}
|
||||
args := fmt.Sprintf(cmdTemplates[userCommand], userName)
|
||||
out, err := execCmd(userCommand, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Failed to add user with error: %v; output: %q", err, string(out))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func createSubordinateRanges(name string) error {
|
||||
|
||||
// first, we should verify that ranges weren't automatically created
|
||||
// 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "v", startID, startID+defaultRangeLen-1, name))
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
out, err := execCmd(userMod, fmt.Sprintf(cmdTemplates[userMod], "w", startID, startID+defaultRangeLen-1, name))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to add subgid range to user: %q; output: %s, err: %v", name, out, err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
sort.Sort(ranges)
|
||||
return findNextRangeStart(ranges)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
sort.Sort(ranges)
|
||||
return findNextRangeStart(ranges)
|
||||
}
|
||||
|
||||
func findNextRangeStart(rangeList ranges) (int, error) {
|
||||
startID := defaultRangeStart
|
||||
for _, arange := range rangeList {
|
||||
if wouldOverlap(arange, startID) {
|
||||
startID = arange.Start + arange.Length
|
||||
}
|
||||
}
|
||||
return startID, nil
|
||||
}
|
||||
|
||||
func wouldOverlap(arange subIDRange, ID int) bool {
|
||||
low := ID
|
||||
high := ID + defaultRangeLen
|
||||
if (low >= arange.Start && low <= arange.Start+arange.Length) ||
|
||||
(high <= arange.Start+arange.Length && high >= arange.Start) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
12
vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go
generated
vendored
12
vendor/github.com/docker/docker/pkg/idtools/usergroupadd_unsupported.go
generated
vendored
@ -1,12 +0,0 @@
|
||||
// +build !linux
|
||||
|
||||
package idtools // import "github.com/docker/docker/pkg/idtools"
|
||||
|
||||
import "fmt"
|
||||
|
||||
// AddNamespaceRangesUser takes a name and finds an unused uid, gid pair
|
||||
// and calls the appropriate helper function to add the group and then
|
||||
// the user to the group in /etc/group and /etc/passwd respectively.
|
||||
func AddNamespaceRangesUser(name string) (int, int, error) {
|
||||
return -1, -1, fmt.Errorf("No support for adding users or groups on this OS")
|
||||
}
|
32
vendor/github.com/docker/docker/pkg/idtools/utils_unix.go
generated
vendored
32
vendor/github.com/docker/docker/pkg/idtools/utils_unix.go
generated
vendored
@ -1,32 +0,0 @@
|
||||
// +build !windows
|
||||
|
||||
package idtools // import "github.com/docker/docker/pkg/idtools"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func resolveBinary(binname string) (string, error) {
|
||||
binaryPath, err := exec.LookPath(binname)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resolvedPath, err := filepath.EvalSymlinks(binaryPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
//only return no error if the final resolved binary basename
|
||||
//matches what was searched for
|
||||
if filepath.Base(resolvedPath) == binname {
|
||||
return resolvedPath, nil
|
||||
}
|
||||
return "", fmt.Errorf("Binary %q does not resolve to a binary of that name in $PATH (%q)", binname, resolvedPath)
|
||||
}
|
||||
|
||||
func execCmd(cmd, args string) ([]byte, error) {
|
||||
execCmd := exec.Command(cmd, strings.Split(args, " ")...)
|
||||
return execCmd.CombinedOutput()
|
||||
}
|
70
vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go
generated
vendored
70
vendor/github.com/rootless-containers/rootlesskit/pkg/child/child.go
generated
vendored
@ -4,6 +4,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"syscall"
|
||||
@ -43,39 +44,33 @@ func mountSysfs() error {
|
||||
return errors.Wrap(err, "creating a directory under /tmp")
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
cmds := [][]string{{"mount", "--rbind", "/sys/fs/cgroup", tmp}}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
return errors.Wrapf(err, "executing %v", cmds)
|
||||
cgroupDir := "/sys/fs/cgroup"
|
||||
if err := unix.Mount(cgroupDir, tmp, "", uintptr(unix.MS_BIND|unix.MS_REC), ""); err != nil {
|
||||
return errors.Wrapf(err, "failed to create bind mount on %s", cgroupDir)
|
||||
}
|
||||
cmds = [][]string{{"mount", "-t", "sysfs", "none", "/sys"}}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
|
||||
if err := unix.Mount("none", "/sys", "sysfs", 0, ""); err != nil {
|
||||
// when the sysfs in the parent namespace is RO,
|
||||
// we can't mount RW sysfs even in the child namespace.
|
||||
// https://github.com/rootless-containers/rootlesskit/pull/23#issuecomment-429292632
|
||||
// https://github.com/torvalds/linux/blob/9f203e2f2f065cd74553e6474f0ae3675f39fb0f/fs/namespace.c#L3326-L3328
|
||||
cmdsRo := [][]string{{"mount", "-t", "sysfs", "-o", "ro", "none", "/sys"}}
|
||||
logrus.Warnf("failed to mount sysfs (%v), falling back to read-only mount (%v): %v",
|
||||
cmds, cmdsRo, err)
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmdsRo); err != nil {
|
||||
logrus.Warnf("failed to mount sysfs, falling back to read-only mount: %v", err)
|
||||
if err := unix.Mount("none", "/sys", "sysfs", uintptr(unix.MS_RDONLY), ""); err != nil {
|
||||
// when /sys/firmware is masked, even RO sysfs can't be mounted
|
||||
logrus.Warnf("failed to mount sysfs (%v): %v", cmdsRo, err)
|
||||
logrus.Warnf("failed to mount sysfs: %v", err)
|
||||
}
|
||||
}
|
||||
cmds = [][]string{{"mount", "-n", "--move", tmp, "/sys/fs/cgroup"}}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
return errors.Wrapf(err, "executing %v", cmds)
|
||||
if err := unix.Mount(tmp, cgroupDir, "", uintptr(unix.MS_MOVE), ""); err != nil {
|
||||
return errors.Wrapf(err, "failed to move mount point from %s to %s", tmp, cgroupDir)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mountProcfs() error {
|
||||
cmds := [][]string{{"mount", "-t", "proc", "none", "/proc"}}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
cmdsRo := [][]string{{"mount", "-t", "proc", "-o", "ro", "none", "/proc"}}
|
||||
logrus.Warnf("failed to mount procfs (%v), falling back to read-only mount (%v): %v",
|
||||
cmds, cmdsRo, err)
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmdsRo); err != nil {
|
||||
logrus.Warnf("failed to mount procfs (%v): %v", cmdsRo, err)
|
||||
if err := unix.Mount("none", "/proc", "proc", 0, ""); err != nil {
|
||||
logrus.Warnf("failed to mount procfs, falling back to read-only mount: %v", err)
|
||||
if err := unix.Mount("none", "/proc", "proc", uintptr(unix.MS_RDONLY), ""); err != nil {
|
||||
logrus.Warnf("failed to mount procfs: %v", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -171,6 +166,7 @@ type Opt struct {
|
||||
CopyUpDirs []string
|
||||
PortDriver port.ChildDriver
|
||||
MountProcfs bool // needs to be set if (and only if) parent.Opt.CreatePIDNS is set
|
||||
Reaper bool
|
||||
}
|
||||
|
||||
func Child(opt Opt) error {
|
||||
@ -242,8 +238,14 @@ func Child(opt Opt) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.Run(); err != nil {
|
||||
return errors.Wrapf(err, "command %v exited", opt.TargetCmd)
|
||||
if opt.Reaper {
|
||||
if err := runAndReap(cmd); err != nil {
|
||||
return errors.Wrapf(err, "command %v exited", opt.TargetCmd)
|
||||
}
|
||||
} else {
|
||||
if err := cmd.Run(); err != nil {
|
||||
return errors.Wrapf(err, "command %v exited", opt.TargetCmd)
|
||||
}
|
||||
}
|
||||
if opt.PortDriver != nil {
|
||||
portQuitCh <- struct{}{}
|
||||
@ -251,3 +253,27 @@ func Child(opt Opt) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runAndReap(cmd *exec.Cmd) error {
|
||||
c := make(chan os.Signal, 32)
|
||||
signal.Notify(c, syscall.SIGCHLD)
|
||||
if err := cmd.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
result := make(chan error)
|
||||
go func() {
|
||||
defer close(result)
|
||||
for range c {
|
||||
for {
|
||||
if pid, err := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); err != nil || pid <= 0 {
|
||||
break
|
||||
} else {
|
||||
if pid == cmd.Process.Pid {
|
||||
result <- cmd.Wait()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
return <-result
|
||||
}
|
||||
|
12
vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go
generated
vendored
12
vendor/github.com/rootless-containers/rootlesskit/pkg/child/hosts.go
generated
vendored
@ -6,9 +6,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/common"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// generateEtcHosts makes sure the current hostname is resolved into
|
||||
@ -56,11 +56,9 @@ func mountEtcHosts(tempDir string) error {
|
||||
if err := ioutil.WriteFile(myEtcHosts, newEtcHosts, 0644); err != nil {
|
||||
return errors.Wrapf(err, "writing %s", myEtcHosts)
|
||||
}
|
||||
cmds := [][]string{
|
||||
{"mount", "--bind", myEtcHosts, "/etc/hosts"},
|
||||
}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
return errors.Wrapf(err, "executing %v", cmds)
|
||||
|
||||
if err := unix.Mount(myEtcHosts, "/etc/hosts", "", uintptr(unix.MS_BIND), ""); err != nil {
|
||||
return errors.Wrapf(err, "failed to create bind mount /etc/hosts for %s", myEtcHosts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
11
vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go
generated
vendored
11
vendor/github.com/rootless-containers/rootlesskit/pkg/child/resolvconf.go
generated
vendored
@ -1,13 +1,12 @@
|
||||
package child
|
||||
|
||||
import (
|
||||
"golang.org/x/sys/unix"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/common"
|
||||
)
|
||||
|
||||
func generateResolvConf(dns string) []byte {
|
||||
@ -36,11 +35,9 @@ func mountResolvConf(tempDir, dns string) error {
|
||||
if err := ioutil.WriteFile(myResolvConf, generateResolvConf(dns), 0644); err != nil {
|
||||
return errors.Wrapf(err, "writing %s", myResolvConf)
|
||||
}
|
||||
cmds := [][]string{
|
||||
{"mount", "--bind", myResolvConf, "/etc/resolv.conf"},
|
||||
}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
return errors.Wrapf(err, "executing %v", cmds)
|
||||
|
||||
if err := unix.Mount(myResolvConf, "/etc/resolv.conf", "", uintptr(unix.MS_BIND), ""); err != nil {
|
||||
return errors.Wrapf(err, "failed to create bind mount /etc/resolv.conf for %s", myResolvConf)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/common"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/copyup"
|
||||
)
|
||||
|
||||
@ -33,24 +34,23 @@ func (d *childDriver) CopyUp(dirs []string) ([]string, error) {
|
||||
// TODO: we can support copy-up /tmp by changing bind0TempDir
|
||||
return copied, errors.New("/tmp cannot be copied up")
|
||||
}
|
||||
cmds := [][]string{
|
||||
// TODO: read-only bind (does not work well for /run)
|
||||
{"mount", "--rbind", d, bind0},
|
||||
{"mount", "-n", "-t", "tmpfs", "none", d},
|
||||
|
||||
if err := unix.Mount(d, bind0, "", uintptr(unix.MS_BIND|unix.MS_REC), ""); err != nil {
|
||||
return copied, errors.Wrapf(err, "failed to create bind mount on %s", d)
|
||||
}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
return copied, errors.Wrapf(err, "executing %v", cmds)
|
||||
|
||||
if err := unix.Mount("none", d, "tmpfs", 0, ""); err != nil {
|
||||
return copied, errors.Wrapf(err, "failed to mount tmpfs on %s", d)
|
||||
}
|
||||
|
||||
bind1, err := ioutil.TempDir(d, ".ro")
|
||||
if err != nil {
|
||||
return copied, errors.Wrapf(err, "creating a directory under %s", d)
|
||||
}
|
||||
cmds = [][]string{
|
||||
{"mount", "-n", "--move", bind0, bind1},
|
||||
}
|
||||
if err := common.Execs(os.Stderr, os.Environ(), cmds); err != nil {
|
||||
return copied, errors.Wrapf(err, "executing %v", cmds)
|
||||
if err := unix.Mount(bind0, bind1, "", uintptr(unix.MS_MOVE), ""); err != nil {
|
||||
return copied, errors.Wrapf(err, "failed to move mount point from %s to %s", bind0, bind1)
|
||||
}
|
||||
|
||||
files, err := ioutil.ReadDir(bind1)
|
||||
if err != nil {
|
||||
return copied, errors.Wrapf(err, "reading dir %s", bind1)
|
||||
|
114
vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go
generated
vendored
114
vendor/github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns/slirp4netns.go
generated
vendored
@ -3,12 +3,16 @@ package slirp4netns
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/common"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/network"
|
||||
@ -16,13 +20,62 @@ import (
|
||||
"github.com/rootless-containers/rootlesskit/pkg/network/parentutils"
|
||||
)
|
||||
|
||||
type Features struct {
|
||||
// SupportsCIDR --cidr (v0.3.0)
|
||||
SupportsCIDR bool
|
||||
// SupportsDisableHostLoopback --disable-host-loopback (v0.3.0)
|
||||
SupportsDisableHostLoopback bool
|
||||
// SupportsAPISocket --api-socket (v0.3.0)
|
||||
SupportsAPISocket bool
|
||||
// SupportsEnableSandbox --enable-sandbox (v0.4.0)
|
||||
SupportsEnableSandbox bool
|
||||
// SupportsEnableSeccomp --enable-seccomp (v0.4.0)
|
||||
SupportsEnableSeccomp bool
|
||||
// KernelSupportsSeccomp whether the kernel supports slirp4netns --enable-seccomp
|
||||
KernelSupportsEnableSeccomp bool
|
||||
}
|
||||
|
||||
func DetectFeatures(binary string) (*Features, error) {
|
||||
if binary == "" {
|
||||
return nil, errors.New("got empty slirp4netns binary")
|
||||
}
|
||||
realBinary, err := exec.LookPath(binary)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "slirp4netns binary %q is not installed", binary)
|
||||
}
|
||||
cmd := exec.Command(realBinary, "--help")
|
||||
cmd.Env = os.Environ()
|
||||
b, err := cmd.CombinedOutput()
|
||||
s := string(b)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err,
|
||||
"command \"%s --help\" failed, make sure slirp4netns v0.2.0+ is installed: %q",
|
||||
realBinary, s)
|
||||
}
|
||||
kernelSupportsEnableSeccomp := false
|
||||
if unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0) != unix.EINVAL {
|
||||
kernelSupportsEnableSeccomp = unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0) != unix.EINVAL
|
||||
}
|
||||
f := Features{
|
||||
SupportsCIDR: strings.Contains(s, "--cidr"),
|
||||
SupportsDisableHostLoopback: strings.Contains(s, "--disable-host-loopback"),
|
||||
SupportsAPISocket: strings.Contains(s, "--api-socket"),
|
||||
SupportsEnableSandbox: strings.Contains(s, "--enable-sandbox"),
|
||||
SupportsEnableSeccomp: strings.Contains(s, "--enable-seccomp"),
|
||||
KernelSupportsEnableSeccomp: kernelSupportsEnableSeccomp,
|
||||
}
|
||||
return &f, nil
|
||||
}
|
||||
|
||||
// NewParentDriver instantiates new parent driver.
|
||||
// ipnet is supported only for slirp4netns v0.3.0+.
|
||||
// ipnet MUST be nil for slirp4netns < v0.3.0.
|
||||
//
|
||||
// disableHostLoopback is supported only for slirp4netns v0.3.0+
|
||||
// apiSocketPath is supported only for slirp4netns v0.3.0+
|
||||
func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopback bool, apiSocketPath string) network.ParentDriver {
|
||||
// enableSandbox is supported only for slirp4netns v0.4.0+
|
||||
// enableSeccomp is supported only for slirp4netns v0.4.0+
|
||||
func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopback bool, apiSocketPath string, enableSandbox, enableSeccomp bool) network.ParentDriver {
|
||||
if binary == "" {
|
||||
panic("got empty slirp4netns binary")
|
||||
}
|
||||
@ -38,6 +91,8 @@ func NewParentDriver(binary string, mtu int, ipnet *net.IPNet, disableHostLoopba
|
||||
ipnet: ipnet,
|
||||
disableHostLoopback: disableHostLoopback,
|
||||
apiSocketPath: apiSocketPath,
|
||||
enableSandbox: enableSandbox,
|
||||
enableSeccomp: enableSeccomp,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,6 +102,8 @@ type parentDriver struct {
|
||||
ipnet *net.IPNet
|
||||
disableHostLoopback bool
|
||||
apiSocketPath string
|
||||
enableSandbox bool
|
||||
enableSeccomp bool
|
||||
}
|
||||
|
||||
func (d *parentDriver) MTU() int {
|
||||
@ -60,7 +117,14 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common.
|
||||
return nil, common.Seq(cleanups), errors.Wrapf(err, "setting up tap %s", tap)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
opts := []string{"--mtu", strconv.Itoa(d.mtu)}
|
||||
readyR, readyW, err := os.Pipe()
|
||||
if err != nil {
|
||||
return nil, common.Seq(cleanups), err
|
||||
}
|
||||
defer readyR.Close()
|
||||
defer readyW.Close()
|
||||
// -r: readyFD
|
||||
opts := []string{"--mtu", strconv.Itoa(d.mtu), "-r", "3"}
|
||||
if d.disableHostLoopback {
|
||||
opts = append(opts, "--disable-host-loopback")
|
||||
}
|
||||
@ -70,10 +134,17 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common.
|
||||
if d.apiSocketPath != "" {
|
||||
opts = append(opts, "--api-socket", d.apiSocketPath)
|
||||
}
|
||||
if d.enableSandbox {
|
||||
opts = append(opts, "--enable-sandbox")
|
||||
}
|
||||
if d.enableSeccomp {
|
||||
opts = append(opts, "--enable-seccomp")
|
||||
}
|
||||
cmd := exec.CommandContext(ctx, d.binary, append(opts, []string{strconv.Itoa(childPID), tap}...)...)
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{
|
||||
Pdeathsig: syscall.SIGKILL,
|
||||
}
|
||||
cmd.ExtraFiles = append(cmd.ExtraFiles, readyW)
|
||||
cleanups = append(cleanups, func() error {
|
||||
logrus.Debugf("killing slirp4netns")
|
||||
cancel()
|
||||
@ -84,6 +155,10 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common.
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, common.Seq(cleanups), errors.Wrapf(err, "executing %v", cmd)
|
||||
}
|
||||
|
||||
if err := waitForReadyFD(cmd.Process.Pid, readyR); err != nil {
|
||||
return nil, common.Seq(cleanups), errors.Wrapf(err, "waiting for ready fd (%v)", cmd)
|
||||
}
|
||||
netmsg := common.NetworkMessage{
|
||||
Dev: tap,
|
||||
MTU: d.mtu,
|
||||
@ -115,6 +190,41 @@ func (d *parentDriver) ConfigureNetwork(childPID int, stateDir string) (*common.
|
||||
return &netmsg, common.Seq(cleanups), nil
|
||||
}
|
||||
|
||||
// waitForReady is from libpod
|
||||
// https://github.com/containers/libpod/blob/e6b843312b93ddaf99d0ef94a7e60ff66bc0eac8/libpod/networking_linux.go#L272-L308
|
||||
func waitForReadyFD(cmdPid int, r *os.File) error {
|
||||
b := make([]byte, 16)
|
||||
for {
|
||||
if err := r.SetDeadline(time.Now().Add(1 * time.Second)); err != nil {
|
||||
return errors.Wrapf(err, "error setting slirp4netns pipe timeout")
|
||||
}
|
||||
if _, err := r.Read(b); err == nil {
|
||||
break
|
||||
} else {
|
||||
if os.IsTimeout(err) {
|
||||
// Check if the process is still running.
|
||||
var status syscall.WaitStatus
|
||||
pid, err := syscall.Wait4(cmdPid, &status, syscall.WNOHANG, nil)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to read slirp4netns process status")
|
||||
}
|
||||
if pid != cmdPid {
|
||||
continue
|
||||
}
|
||||
if status.Exited() {
|
||||
return errors.New("slirp4netns failed")
|
||||
}
|
||||
if status.Signaled() {
|
||||
return errors.New("slirp4netns killed by signal")
|
||||
}
|
||||
continue
|
||||
}
|
||||
return errors.Wrapf(err, "failed to read from slirp4netns sync pipe")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewChildDriver() network.ChildDriver {
|
||||
return &childDriver{}
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
package idtools // import "github.com/docker/docker/pkg/idtools"
|
||||
// Package idtools is forked from https://github.com/moby/moby/tree/c12f09bf99b54f274a5ae241dd154fa74020cbab/pkg/idtools
|
||||
package idtools
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@ -33,28 +35,6 @@ const (
|
||||
subgidFileName = "/etc/subgid"
|
||||
)
|
||||
|
||||
// MkdirAllAndChown creates a directory (include any along the path) and then modifies
|
||||
// ownership to the requested uid/gid. If the directory already exists, this
|
||||
// function will still change ownership to the requested uid/gid pair.
|
||||
func MkdirAllAndChown(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, true, true)
|
||||
}
|
||||
|
||||
// MkdirAndChown creates a directory and then modifies ownership to the requested uid/gid.
|
||||
// If the directory already exists, this function still changes ownership.
|
||||
// Note that unlike os.Mkdir(), this function does not return IsExist error
|
||||
// in case path already exists.
|
||||
func MkdirAndChown(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, false, true)
|
||||
}
|
||||
|
||||
// MkdirAllAndChownNew creates a directory (include any along the path) and then modifies
|
||||
// ownership ONLY of newly created directories to the requested uid/gid. If the
|
||||
// directories along the path exist, no change of ownership will be performed
|
||||
func MkdirAllAndChownNew(path string, mode os.FileMode, owner Identity) error {
|
||||
return mkdirAs(path, mode, owner, true, false)
|
||||
}
|
||||
|
||||
// GetRootUIDGID retrieves the remapped root uid/gid pair from the set of maps.
|
||||
// If the maps are empty, then the root uid/gid will default to "real" 0/0
|
||||
func GetRootUIDGID(uidMap, gidMap []IDMap) (int, int, error) {
|
||||
@ -202,6 +182,8 @@ func (i *IdentityMapping) GIDs() []IDMap {
|
||||
func createIDMap(subidRanges ranges) []IDMap {
|
||||
idMap := []IDMap{}
|
||||
|
||||
// sort the ranges by lowest ID first
|
||||
sort.Sort(subidRanges)
|
||||
containerID := 0
|
||||
for _, idrange := range subidRanges {
|
||||
idMap = append(idMap, IDMap{
|
12
vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go
generated
vendored
12
vendor/github.com/rootless-containers/rootlesskit/pkg/parent/parent.go
generated
vendored
@ -12,7 +12,6 @@ import (
|
||||
"strconv"
|
||||
"syscall"
|
||||
|
||||
"github.com/docker/docker/pkg/idtools"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -22,6 +21,7 @@ import (
|
||||
"github.com/rootless-containers/rootlesskit/pkg/common"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/msgutil"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/network"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/parent/idtools"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
)
|
||||
|
||||
@ -103,10 +103,6 @@ func Parent(opt Opt) error {
|
||||
if err := cmd.Start(); err != nil {
|
||||
return errors.Wrap(err, "failed to start the child")
|
||||
}
|
||||
childPIDPath := filepath.Join(opt.StateDir, StateFileChildPID)
|
||||
if err := ioutil.WriteFile(childPIDPath, []byte(strconv.Itoa(cmd.Process.Pid)), 0444); err != nil {
|
||||
return errors.Wrapf(err, "failed to write the child PID %d to %s", cmd.Process.Pid, childPIDPath)
|
||||
}
|
||||
if err := setupUIDGIDMap(cmd.Process.Pid); err != nil {
|
||||
return errors.Wrap(err, "failed to setup UID/GID map")
|
||||
}
|
||||
@ -176,6 +172,12 @@ func Parent(opt Opt) error {
|
||||
logrus.Debugf("published port %v", st)
|
||||
}
|
||||
}
|
||||
|
||||
// after child is fully configured, write PID to child_pid file
|
||||
childPIDPath := filepath.Join(opt.StateDir, StateFileChildPID)
|
||||
if err := ioutil.WriteFile(childPIDPath, []byte(strconv.Itoa(cmd.Process.Pid)), 0444); err != nil {
|
||||
return errors.Wrapf(err, "failed to write the child PID %d to %s", cmd.Process.Pid, childPIDPath)
|
||||
}
|
||||
// listens the API
|
||||
apiSockPath := filepath.Join(opt.StateDir, StateFileAPISock)
|
||||
apiCloser, err := listenServeAPI(apiSockPath, &router.Backend{PortDriver: opt.PortDriver})
|
||||
|
483
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/builtin.go
generated
vendored
483
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/builtin.go
generated
vendored
@ -1,487 +1,14 @@
|
||||
package builtin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/msgutil"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/portutil"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/child"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent"
|
||||
)
|
||||
|
||||
const (
|
||||
opaqueKeySocketPath = "builtin.socketpath"
|
||||
opaqueKeyChildReadyPipePath = "builtin.readypipepath"
|
||||
var (
|
||||
NewParentDriver func(logWriter io.Writer, stateDir string) (port.ParentDriver, error) = parent.NewDriver
|
||||
NewChildDriver func(logWriter io.Writer) port.ChildDriver = child.NewDriver
|
||||
)
|
||||
|
||||
// NewParentDriver for builtin driver.
|
||||
func NewParentDriver(logWriter io.Writer, stateDir string) (port.ParentDriver, error) {
|
||||
// TODO: consider using socketpair FD instead of socket file
|
||||
socketPath := filepath.Join(stateDir, ".bp.sock")
|
||||
childReadyPipePath := filepath.Join(stateDir, ".bp-ready.pipe")
|
||||
// remove the path just incase the previous rootlesskit instance crashed
|
||||
if err := os.RemoveAll(childReadyPipePath); err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot remove %s", childReadyPipePath)
|
||||
}
|
||||
if err := syscall.Mkfifo(childReadyPipePath, 0600); err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot mkfifo %s", childReadyPipePath)
|
||||
}
|
||||
d := driver{
|
||||
logWriter: logWriter,
|
||||
socketPath: socketPath,
|
||||
childReadyPipePath: childReadyPipePath,
|
||||
ports: make(map[int]*port.Status, 0),
|
||||
stoppers: make(map[int]func() error, 0),
|
||||
nextID: 1,
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
logWriter io.Writer
|
||||
socketPath string
|
||||
childReadyPipePath string
|
||||
mu sync.Mutex
|
||||
ports map[int]*port.Status
|
||||
stoppers map[int]func() error
|
||||
nextID int
|
||||
}
|
||||
|
||||
func (d *driver) OpaqueForChild() map[string]string {
|
||||
return map[string]string{
|
||||
opaqueKeySocketPath: d.socketPath,
|
||||
opaqueKeyChildReadyPipePath: d.childReadyPipePath,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) RunParentDriver(initComplete chan struct{}, quit <-chan struct{}, _ *port.ChildContext) error {
|
||||
childReadyPipeR, err := os.OpenFile(d.childReadyPipePath, os.O_RDONLY, os.ModeNamedPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = ioutil.ReadAll(childReadyPipeR); err != nil {
|
||||
return err
|
||||
}
|
||||
childReadyPipeR.Close()
|
||||
var dialer net.Dialer
|
||||
conn, err := dialer.Dial("unix", d.socketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = initiate(conn.(*net.UnixConn))
|
||||
conn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initComplete <- struct{}{}
|
||||
<-quit
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) {
|
||||
d.mu.Lock()
|
||||
err := portutil.ValidatePortSpec(spec, d.ports)
|
||||
d.mu.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routineStopCh := make(chan struct{})
|
||||
routineStop := func() error {
|
||||
close(routineStopCh)
|
||||
return nil // FIXME
|
||||
}
|
||||
switch spec.Proto {
|
||||
case "tcp":
|
||||
err = startTCPRoutines(d.socketPath, spec, routineStopCh, d.logWriter)
|
||||
case "udp":
|
||||
err = startUDPRoutines(d.socketPath, spec, routineStopCh, d.logWriter)
|
||||
default:
|
||||
// NOTREACHED
|
||||
return nil, errors.New("spec was not validated?")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.mu.Lock()
|
||||
id := d.nextID
|
||||
st := port.Status{
|
||||
ID: id,
|
||||
Spec: spec,
|
||||
}
|
||||
d.ports[id] = &st
|
||||
d.stoppers[id] = routineStop
|
||||
d.nextID++
|
||||
d.mu.Unlock()
|
||||
return &st, nil
|
||||
}
|
||||
|
||||
func (d *driver) ListPorts(ctx context.Context) ([]port.Status, error) {
|
||||
var ports []port.Status
|
||||
d.mu.Lock()
|
||||
for _, p := range d.ports {
|
||||
ports = append(ports, *p)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
func (d *driver) RemovePort(ctx context.Context, id int) error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
stop, ok := d.stoppers[id]
|
||||
if !ok {
|
||||
return errors.Errorf("unknown id: %d", id)
|
||||
}
|
||||
err := stop()
|
||||
delete(d.stoppers, id)
|
||||
delete(d.ports, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func initiate(c *net.UnixConn) error {
|
||||
req := request{
|
||||
Type: requestTypeInit,
|
||||
}
|
||||
if _, err := msgutil.MarshalToWriter(c, &req); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.CloseWrite(); err != nil {
|
||||
return err
|
||||
}
|
||||
var rep reply
|
||||
if _, err := msgutil.UnmarshalFromReader(c, &rep); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.CloseRead()
|
||||
}
|
||||
|
||||
func connectToChild(socketPath string, spec port.Spec) (int, error) {
|
||||
var dialer net.Dialer
|
||||
conn, err := dialer.Dial("unix", socketPath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer conn.Close()
|
||||
c := conn.(*net.UnixConn)
|
||||
req := request{
|
||||
Type: requestTypeConnect,
|
||||
Proto: spec.Proto,
|
||||
Port: spec.ChildPort,
|
||||
}
|
||||
if _, err := msgutil.MarshalToWriter(c, &req); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := c.CloseWrite(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
oobSpace := unix.CmsgSpace(4)
|
||||
oob := make([]byte, oobSpace)
|
||||
_, oobN, _, _, err := c.ReadMsgUnix(nil, oob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if oobN != oobSpace {
|
||||
return 0, errors.Errorf("expected OOB space %d, got %d", oobSpace, oobN)
|
||||
}
|
||||
oob = oob[:oobN]
|
||||
fd, err := parseFDFromOOB(oob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := c.CloseRead(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
func connectToChildWithRetry(socketPath string, spec port.Spec, retries int) (int, error) {
|
||||
for i := 0; i < retries; i++ {
|
||||
fd, err := connectToChild(socketPath, spec)
|
||||
if i == retries-1 && err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err == nil {
|
||||
return fd, err
|
||||
}
|
||||
// TODO: backoff
|
||||
time.Sleep(time.Duration(i*5) * time.Millisecond)
|
||||
}
|
||||
// NOT REACHED
|
||||
return 0, errors.New("reached max retry")
|
||||
}
|
||||
|
||||
func parseFDFromOOB(oob []byte) (int, error) {
|
||||
scms, err := unix.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(scms) != 1 {
|
||||
return 0, errors.Errorf("unexpected scms: %v", scms)
|
||||
}
|
||||
scm := scms[0]
|
||||
fds, err := unix.ParseUnixRights(&scm)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(fds) != 1 {
|
||||
return 0, errors.Errorf("unexpected fds: %v", fds)
|
||||
}
|
||||
return fds[0], nil
|
||||
}
|
||||
|
||||
func startTCPRoutines(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
|
||||
ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort))
|
||||
if err != nil {
|
||||
fmt.Fprintf(logWriter, "listen: %v\n", err)
|
||||
return err
|
||||
}
|
||||
newConns := make(chan net.Conn)
|
||||
go func() {
|
||||
for {
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
fmt.Fprintf(logWriter, "accept: %v\n", err)
|
||||
close(newConns)
|
||||
return
|
||||
}
|
||||
newConns <- c
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
for {
|
||||
select {
|
||||
case c, ok := <-newConns:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil {
|
||||
fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
// no wait
|
||||
return nil
|
||||
}
|
||||
|
||||
func startUDPRoutines(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
|
||||
addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := net.ListenUDP("udp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil {
|
||||
fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
// no wait
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyConnToChild(c net.Conn, socketPath string, spec port.Spec, stopCh <-chan struct{}) error {
|
||||
defer c.Close()
|
||||
// get fd from the child as an SCM_RIGHTS cmsg
|
||||
fd, err := connectToChildWithRetry(socketPath, spec, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f := os.NewFile(uintptr(fd), "")
|
||||
defer f.Close()
|
||||
fc, err := net.FileConn(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fc.Close()
|
||||
bicopy(c, fc, stopCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// bicopy is based on libnetwork/cmd/proxy/tcp_proxy.go .
|
||||
// NOTE: sendfile(2) cannot be used for sockets
|
||||
func bicopy(x, y net.Conn, quit <-chan struct{}) {
|
||||
var wg sync.WaitGroup
|
||||
var broker = func(to, from net.Conn) {
|
||||
io.Copy(to, from)
|
||||
if fromTCP, ok := from.(*net.TCPConn); ok {
|
||||
fromTCP.CloseRead()
|
||||
}
|
||||
if toTCP, ok := to.(*net.TCPConn); ok {
|
||||
toTCP.CloseWrite()
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
wg.Add(2)
|
||||
go broker(x, y)
|
||||
go broker(y, x)
|
||||
finish := make(chan struct{})
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(finish)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-quit:
|
||||
case <-finish:
|
||||
}
|
||||
x.Close()
|
||||
y.Close()
|
||||
<-finish
|
||||
}
|
||||
|
||||
const (
|
||||
requestTypeInit = "init"
|
||||
requestTypeConnect = "connect"
|
||||
)
|
||||
|
||||
// request and response are encoded as JSON with uint32le length header.
|
||||
type request struct {
|
||||
Type string // "init" or "connect"
|
||||
Proto string // "tcp" or "udp"
|
||||
Port int
|
||||
}
|
||||
|
||||
// may contain FD as OOB
|
||||
type reply struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
func NewChildDriver(logWriter io.Writer) port.ChildDriver {
|
||||
return &childDriver{
|
||||
logWriter: logWriter,
|
||||
}
|
||||
}
|
||||
|
||||
type childDriver struct {
|
||||
logWriter io.Writer
|
||||
}
|
||||
|
||||
func (d *childDriver) RunChildDriver(opaque map[string]string, quit <-chan struct{}) error {
|
||||
socketPath := opaque[opaqueKeySocketPath]
|
||||
if socketPath == "" {
|
||||
return errors.New("socket path not set")
|
||||
}
|
||||
childReadyPipePath := opaque[opaqueKeyChildReadyPipePath]
|
||||
if childReadyPipePath == "" {
|
||||
return errors.New("child ready pipe path not set")
|
||||
}
|
||||
childReadyPipeW, err := os.OpenFile(childReadyPipePath, os.O_WRONLY, os.ModeNamedPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ln, err := net.ListenUnix("unix", &net.UnixAddr{
|
||||
Name: socketPath,
|
||||
Net: "unix",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// write nothing, just close
|
||||
if err = childReadyPipeW.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
stopAccept := make(chan struct{}, 1)
|
||||
go func() {
|
||||
<-quit
|
||||
stopAccept <- struct{}{}
|
||||
ln.Close()
|
||||
}()
|
||||
for {
|
||||
c, err := ln.AcceptUnix()
|
||||
if err != nil {
|
||||
select {
|
||||
case <-stopAccept:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if rerr := d.routine(c); rerr != nil {
|
||||
rep := reply{
|
||||
Error: rerr.Error(),
|
||||
}
|
||||
msgutil.MarshalToWriter(c, &rep)
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *childDriver) routine(c *net.UnixConn) error {
|
||||
var req request
|
||||
if _, err := msgutil.UnmarshalFromReader(c, &req); err != nil {
|
||||
return err
|
||||
}
|
||||
switch req.Type {
|
||||
case requestTypeInit:
|
||||
return d.handleConnectInit(c, &req)
|
||||
case requestTypeConnect:
|
||||
return d.handleConnectRequest(c, &req)
|
||||
default:
|
||||
return errors.Errorf("unknown request type %q", req.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *childDriver) handleConnectInit(c *net.UnixConn, req *request) error {
|
||||
_, err := msgutil.MarshalToWriter(c, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *request) error {
|
||||
switch req.Proto {
|
||||
case "tcp":
|
||||
case "udp":
|
||||
default:
|
||||
return errors.Errorf("unknown proto: %q", req.Proto)
|
||||
}
|
||||
var dialer net.Dialer
|
||||
targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("127.0.0.1:%d", req.Port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer targetConn.Close() // no effect on duplicated FD
|
||||
targetConnFiler, ok := targetConn.(filer)
|
||||
if !ok {
|
||||
return errors.Errorf("unknown target connection: %+v", targetConn)
|
||||
}
|
||||
targetConnFile, err := targetConnFiler.File()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oob := unix.UnixRights(int(targetConnFile.Fd()))
|
||||
f, err := c.File()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = unix.Sendmsg(int(f.Fd()), []byte("dummy"), oob, nil, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// filer is implemented by *net.TCPConn and *net.UDPConn
|
||||
type filer interface {
|
||||
File() (f *os.File, err error)
|
||||
}
|
||||
|
134
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go
generated
vendored
Normal file
134
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/child/child.go
generated
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
package child
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/msgutil"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
|
||||
opaquepkg "github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque"
|
||||
)
|
||||
|
||||
func NewDriver(logWriter io.Writer) port.ChildDriver {
|
||||
return &childDriver{
|
||||
logWriter: logWriter,
|
||||
}
|
||||
}
|
||||
|
||||
type childDriver struct {
|
||||
logWriter io.Writer
|
||||
}
|
||||
|
||||
func (d *childDriver) RunChildDriver(opaque map[string]string, quit <-chan struct{}) error {
|
||||
socketPath := opaque[opaquepkg.SocketPath]
|
||||
if socketPath == "" {
|
||||
return errors.New("socket path not set")
|
||||
}
|
||||
childReadyPipePath := opaque[opaquepkg.ChildReadyPipePath]
|
||||
if childReadyPipePath == "" {
|
||||
return errors.New("child ready pipe path not set")
|
||||
}
|
||||
childReadyPipeW, err := os.OpenFile(childReadyPipePath, os.O_WRONLY, os.ModeNamedPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ln, err := net.ListenUnix("unix", &net.UnixAddr{
|
||||
Name: socketPath,
|
||||
Net: "unix",
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// write nothing, just close
|
||||
if err = childReadyPipeW.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
stopAccept := make(chan struct{}, 1)
|
||||
go func() {
|
||||
<-quit
|
||||
stopAccept <- struct{}{}
|
||||
ln.Close()
|
||||
}()
|
||||
for {
|
||||
c, err := ln.AcceptUnix()
|
||||
if err != nil {
|
||||
select {
|
||||
case <-stopAccept:
|
||||
return nil
|
||||
default:
|
||||
}
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
if rerr := d.routine(c); rerr != nil {
|
||||
rep := msg.Reply{
|
||||
Error: rerr.Error(),
|
||||
}
|
||||
msgutil.MarshalToWriter(c, &rep)
|
||||
}
|
||||
c.Close()
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *childDriver) routine(c *net.UnixConn) error {
|
||||
var req msg.Request
|
||||
if _, err := msgutil.UnmarshalFromReader(c, &req); err != nil {
|
||||
return err
|
||||
}
|
||||
switch req.Type {
|
||||
case msg.RequestTypeInit:
|
||||
return d.handleConnectInit(c, &req)
|
||||
case msg.RequestTypeConnect:
|
||||
return d.handleConnectRequest(c, &req)
|
||||
default:
|
||||
return errors.Errorf("unknown request type %q", req.Type)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *childDriver) handleConnectInit(c *net.UnixConn, req *msg.Request) error {
|
||||
_, err := msgutil.MarshalToWriter(c, nil)
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *childDriver) handleConnectRequest(c *net.UnixConn, req *msg.Request) error {
|
||||
switch req.Proto {
|
||||
case "tcp":
|
||||
case "udp":
|
||||
default:
|
||||
return errors.Errorf("unknown proto: %q", req.Proto)
|
||||
}
|
||||
var dialer net.Dialer
|
||||
targetConn, err := dialer.Dial(req.Proto, fmt.Sprintf("127.0.0.1:%d", req.Port))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer targetConn.Close() // no effect on duplicated FD
|
||||
targetConnFiler, ok := targetConn.(filer)
|
||||
if !ok {
|
||||
return errors.Errorf("unknown target connection: %+v", targetConn)
|
||||
}
|
||||
targetConnFile, err := targetConnFiler.File()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
oob := unix.UnixRights(int(targetConnFile.Fd()))
|
||||
f, err := c.File()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = unix.Sendmsg(int(f.Fd()), []byte("dummy"), oob, nil, 0)
|
||||
return err
|
||||
}
|
||||
|
||||
// filer is implemented by *net.TCPConn and *net.UDPConn
|
||||
type filer interface {
|
||||
File() (f *os.File, err error)
|
||||
}
|
129
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg/msg.go
generated
vendored
Normal file
129
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg/msg.go
generated
vendored
Normal file
@ -0,0 +1,129 @@
|
||||
package msg
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/msgutil"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
)
|
||||
|
||||
const (
|
||||
RequestTypeInit = "init"
|
||||
RequestTypeConnect = "connect"
|
||||
)
|
||||
|
||||
// Request and Response are encoded as JSON with uint32le length header.
|
||||
type Request struct {
|
||||
Type string // "init" or "connect"
|
||||
Proto string // "tcp" or "udp"
|
||||
Port int
|
||||
}
|
||||
|
||||
// Reply may contain FD as OOB
|
||||
type Reply struct {
|
||||
Error string
|
||||
}
|
||||
|
||||
// Initiate sends "init" request to the child UNIX socket.
|
||||
func Initiate(c *net.UnixConn) error {
|
||||
req := Request{
|
||||
Type: RequestTypeInit,
|
||||
}
|
||||
if _, err := msgutil.MarshalToWriter(c, &req); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.CloseWrite(); err != nil {
|
||||
return err
|
||||
}
|
||||
var rep Reply
|
||||
if _, err := msgutil.UnmarshalFromReader(c, &rep); err != nil {
|
||||
return err
|
||||
}
|
||||
return c.CloseRead()
|
||||
}
|
||||
|
||||
// ConnectToChild connects to the child UNIX socket, and obtains TCP or UDP socket FD
|
||||
// that corresponds to the port spec.
|
||||
func ConnectToChild(c *net.UnixConn, spec port.Spec) (int, error) {
|
||||
req := Request{
|
||||
Type: RequestTypeConnect,
|
||||
Proto: spec.Proto,
|
||||
Port: spec.ChildPort,
|
||||
}
|
||||
if _, err := msgutil.MarshalToWriter(c, &req); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := c.CloseWrite(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
oobSpace := unix.CmsgSpace(4)
|
||||
oob := make([]byte, oobSpace)
|
||||
_, oobN, _, _, err := c.ReadMsgUnix(nil, oob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if oobN != oobSpace {
|
||||
return 0, errors.Errorf("expected OOB space %d, got %d", oobSpace, oobN)
|
||||
}
|
||||
oob = oob[:oobN]
|
||||
fd, err := parseFDFromOOB(oob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err := c.CloseRead(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// ConnectToChildWithSocketPath wraps ConnectToChild
|
||||
func ConnectToChildWithSocketPath(socketPath string, spec port.Spec) (int, error) {
|
||||
var dialer net.Dialer
|
||||
conn, err := dialer.Dial("unix", socketPath)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer conn.Close()
|
||||
c := conn.(*net.UnixConn)
|
||||
return ConnectToChild(c, spec)
|
||||
}
|
||||
|
||||
// ConnectToChildWithRetry retries ConnectToChild every (i*5) milliseconds.
|
||||
func ConnectToChildWithRetry(socketPath string, spec port.Spec, retries int) (int, error) {
|
||||
for i := 0; i < retries; i++ {
|
||||
fd, err := ConnectToChildWithSocketPath(socketPath, spec)
|
||||
if i == retries-1 && err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if err == nil {
|
||||
return fd, err
|
||||
}
|
||||
// TODO: backoff
|
||||
time.Sleep(time.Duration(i*5) * time.Millisecond)
|
||||
}
|
||||
// NOT REACHED
|
||||
return 0, errors.New("reached max retry")
|
||||
}
|
||||
|
||||
func parseFDFromOOB(oob []byte) (int, error) {
|
||||
scms, err := unix.ParseSocketControlMessage(oob)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(scms) != 1 {
|
||||
return 0, errors.Errorf("unexpected scms: %v", scms)
|
||||
}
|
||||
scm := scms[0]
|
||||
fds, err := unix.ParseUnixRights(&scm)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(fds) != 1 {
|
||||
return 0, errors.Errorf("unexpected fds: %v", fds)
|
||||
}
|
||||
return fds[0], nil
|
||||
}
|
6
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque/opaque.go
generated
vendored
Normal file
6
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque/opaque.go
generated
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
package opaque
|
||||
|
||||
const (
|
||||
SocketPath = "builtin.socketpath"
|
||||
ChildReadyPipePath = "builtin.readypipepath"
|
||||
)
|
145
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go
generated
vendored
Normal file
145
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/parent.go
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
package parent
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/portutil"
|
||||
)
|
||||
|
||||
// NewDriver for builtin driver.
|
||||
func NewDriver(logWriter io.Writer, stateDir string) (port.ParentDriver, error) {
|
||||
// TODO: consider using socketpair FD instead of socket file
|
||||
socketPath := filepath.Join(stateDir, ".bp.sock")
|
||||
childReadyPipePath := filepath.Join(stateDir, ".bp-ready.pipe")
|
||||
// remove the path just in case the previous rootlesskit instance crashed
|
||||
if err := os.RemoveAll(childReadyPipePath); err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot remove %s", childReadyPipePath)
|
||||
}
|
||||
if err := syscall.Mkfifo(childReadyPipePath, 0600); err != nil {
|
||||
return nil, errors.Wrapf(err, "cannot mkfifo %s", childReadyPipePath)
|
||||
}
|
||||
d := driver{
|
||||
logWriter: logWriter,
|
||||
socketPath: socketPath,
|
||||
childReadyPipePath: childReadyPipePath,
|
||||
ports: make(map[int]*port.Status, 0),
|
||||
stoppers: make(map[int]func() error, 0),
|
||||
nextID: 1,
|
||||
}
|
||||
return &d, nil
|
||||
}
|
||||
|
||||
type driver struct {
|
||||
logWriter io.Writer
|
||||
socketPath string
|
||||
childReadyPipePath string
|
||||
mu sync.Mutex
|
||||
ports map[int]*port.Status
|
||||
stoppers map[int]func() error
|
||||
nextID int
|
||||
}
|
||||
|
||||
func (d *driver) OpaqueForChild() map[string]string {
|
||||
return map[string]string{
|
||||
opaque.SocketPath: d.socketPath,
|
||||
opaque.ChildReadyPipePath: d.childReadyPipePath,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) RunParentDriver(initComplete chan struct{}, quit <-chan struct{}, _ *port.ChildContext) error {
|
||||
childReadyPipeR, err := os.OpenFile(d.childReadyPipePath, os.O_RDONLY, os.ModeNamedPipe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = ioutil.ReadAll(childReadyPipeR); err != nil {
|
||||
return err
|
||||
}
|
||||
childReadyPipeR.Close()
|
||||
var dialer net.Dialer
|
||||
conn, err := dialer.Dial("unix", d.socketPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = msg.Initiate(conn.(*net.UnixConn))
|
||||
conn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
initComplete <- struct{}{}
|
||||
<-quit
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, error) {
|
||||
d.mu.Lock()
|
||||
err := portutil.ValidatePortSpec(spec, d.ports)
|
||||
d.mu.Unlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
routineStopCh := make(chan struct{})
|
||||
routineStop := func() error {
|
||||
close(routineStopCh)
|
||||
return nil // FIXME
|
||||
}
|
||||
switch spec.Proto {
|
||||
case "tcp":
|
||||
err = tcp.Run(d.socketPath, spec, routineStopCh, d.logWriter)
|
||||
case "udp":
|
||||
err = udp.Run(d.socketPath, spec, routineStopCh, d.logWriter)
|
||||
default:
|
||||
// NOTREACHED
|
||||
return nil, errors.New("spec was not validated?")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
d.mu.Lock()
|
||||
id := d.nextID
|
||||
st := port.Status{
|
||||
ID: id,
|
||||
Spec: spec,
|
||||
}
|
||||
d.ports[id] = &st
|
||||
d.stoppers[id] = routineStop
|
||||
d.nextID++
|
||||
d.mu.Unlock()
|
||||
return &st, nil
|
||||
}
|
||||
|
||||
func (d *driver) ListPorts(ctx context.Context) ([]port.Status, error) {
|
||||
var ports []port.Status
|
||||
d.mu.Lock()
|
||||
for _, p := range d.ports {
|
||||
ports = append(ports, *p)
|
||||
}
|
||||
d.mu.Unlock()
|
||||
return ports, nil
|
||||
}
|
||||
|
||||
func (d *driver) RemovePort(ctx context.Context, id int) error {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
stop, ok := d.stoppers[id]
|
||||
if !ok {
|
||||
return errors.Errorf("unknown id: %d", id)
|
||||
}
|
||||
err := stop()
|
||||
delete(d.stoppers, id)
|
||||
delete(d.ports, id)
|
||||
return err
|
||||
}
|
104
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go
generated
vendored
Normal file
104
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp/tcp.go
generated
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
package tcp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
|
||||
)
|
||||
|
||||
func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
|
||||
ln, err := net.Listen("tcp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort))
|
||||
if err != nil {
|
||||
fmt.Fprintf(logWriter, "listen: %v\n", err)
|
||||
return err
|
||||
}
|
||||
newConns := make(chan net.Conn)
|
||||
go func() {
|
||||
for {
|
||||
c, err := ln.Accept()
|
||||
if err != nil {
|
||||
fmt.Fprintf(logWriter, "accept: %v\n", err)
|
||||
close(newConns)
|
||||
return
|
||||
}
|
||||
newConns <- c
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer ln.Close()
|
||||
for {
|
||||
select {
|
||||
case c, ok := <-newConns:
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
if err := copyConnToChild(c, socketPath, spec, stopCh); err != nil {
|
||||
fmt.Fprintf(logWriter, "copyConnToChild: %v\n", err)
|
||||
return
|
||||
}
|
||||
}()
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
// no wait
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyConnToChild(c net.Conn, socketPath string, spec port.Spec, stopCh <-chan struct{}) error {
|
||||
defer c.Close()
|
||||
// get fd from the child as an SCM_RIGHTS cmsg
|
||||
fd, err := msg.ConnectToChildWithRetry(socketPath, spec, 10)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f := os.NewFile(uintptr(fd), "")
|
||||
defer f.Close()
|
||||
fc, err := net.FileConn(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fc.Close()
|
||||
bicopy(c, fc, stopCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// bicopy is based on libnetwork/cmd/proxy/tcp_proxy.go .
|
||||
// NOTE: sendfile(2) cannot be used for sockets
|
||||
func bicopy(x, y net.Conn, quit <-chan struct{}) {
|
||||
var wg sync.WaitGroup
|
||||
var broker = func(to, from net.Conn) {
|
||||
io.Copy(to, from)
|
||||
if fromTCP, ok := from.(*net.TCPConn); ok {
|
||||
fromTCP.CloseRead()
|
||||
}
|
||||
if toTCP, ok := to.(*net.TCPConn); ok {
|
||||
toTCP.CloseWrite()
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
|
||||
wg.Add(2)
|
||||
go broker(x, y)
|
||||
go broker(y, x)
|
||||
finish := make(chan struct{})
|
||||
go func() {
|
||||
wg.Wait()
|
||||
close(finish)
|
||||
}()
|
||||
|
||||
select {
|
||||
case <-quit:
|
||||
case <-finish:
|
||||
}
|
||||
x.Close()
|
||||
y.Close()
|
||||
<-finish
|
||||
}
|
60
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udp.go
generated
vendored
Normal file
60
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udp.go
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
package udp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
|
||||
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy"
|
||||
)
|
||||
|
||||
func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
|
||||
addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", spec.ParentIP, spec.ParentPort))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c, err := net.ListenUDP("udp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
udpp := &udpproxy.UDPProxy{
|
||||
LogWriter: logWriter,
|
||||
Listener: c,
|
||||
BackendDial: func() (*net.UDPConn, error) {
|
||||
// get fd from the child as an SCM_RIGHTS cmsg
|
||||
fd, err := msg.ConnectToChildWithRetry(socketPath, spec, 10)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f := os.NewFile(uintptr(fd), "")
|
||||
defer f.Close()
|
||||
fc, err := net.FileConn(f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uc, ok := fc.(*net.UDPConn)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("file conn doesn't implement *net.UDPConn: %+v", fc)
|
||||
}
|
||||
return uc, nil
|
||||
},
|
||||
}
|
||||
go udpp.Run()
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-stopCh:
|
||||
// udpp.Close closes ln as well
|
||||
udpp.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
// no wait
|
||||
return nil
|
||||
}
|
150
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy/udp_proxy.go
generated
vendored
Normal file
150
vendor/github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy/udp_proxy.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
// Package udpproxy is from https://raw.githubusercontent.com/docker/libnetwork/fec6476dfa21380bf8ee4d74048515d968c1ee63/cmd/proxy/udp_proxy.go
|
||||
package udpproxy
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// UDPConnTrackTimeout is the timeout used for UDP connection tracking
|
||||
UDPConnTrackTimeout = 90 * time.Second
|
||||
// UDPBufSize is the buffer size for the UDP proxy
|
||||
UDPBufSize = 65507
|
||||
)
|
||||
|
||||
// A net.Addr where the IP is split into two fields so you can use it as a key
|
||||
// in a map:
|
||||
type connTrackKey struct {
|
||||
IPHigh uint64
|
||||
IPLow uint64
|
||||
Port int
|
||||
}
|
||||
|
||||
func newConnTrackKey(addr *net.UDPAddr) *connTrackKey {
|
||||
if len(addr.IP) == net.IPv4len {
|
||||
return &connTrackKey{
|
||||
IPHigh: 0,
|
||||
IPLow: uint64(binary.BigEndian.Uint32(addr.IP)),
|
||||
Port: addr.Port,
|
||||
}
|
||||
}
|
||||
return &connTrackKey{
|
||||
IPHigh: binary.BigEndian.Uint64(addr.IP[:8]),
|
||||
IPLow: binary.BigEndian.Uint64(addr.IP[8:]),
|
||||
Port: addr.Port,
|
||||
}
|
||||
}
|
||||
|
||||
type connTrackMap map[connTrackKey]*net.UDPConn
|
||||
|
||||
// UDPProxy is proxy for which handles UDP datagrams.
|
||||
// From libnetwork udp_proxy.go .
|
||||
type UDPProxy struct {
|
||||
LogWriter io.Writer
|
||||
Listener *net.UDPConn
|
||||
BackendDial func() (*net.UDPConn, error)
|
||||
connTrackTable connTrackMap
|
||||
connTrackLock sync.Mutex
|
||||
}
|
||||
|
||||
func (proxy *UDPProxy) replyLoop(proxyConn *net.UDPConn, clientAddr *net.UDPAddr, clientKey *connTrackKey) {
|
||||
defer func() {
|
||||
proxy.connTrackLock.Lock()
|
||||
delete(proxy.connTrackTable, *clientKey)
|
||||
proxy.connTrackLock.Unlock()
|
||||
proxyConn.Close()
|
||||
}()
|
||||
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
for {
|
||||
proxyConn.SetReadDeadline(time.Now().Add(UDPConnTrackTimeout))
|
||||
again:
|
||||
read, err := proxyConn.Read(readBuf)
|
||||
if err != nil {
|
||||
if err, ok := err.(*net.OpError); ok && err.Err == syscall.ECONNREFUSED {
|
||||
// This will happen if the last write failed
|
||||
// (e.g: nothing is actually listening on the
|
||||
// proxied port on the container), ignore it
|
||||
// and continue until UDPConnTrackTimeout
|
||||
// expires:
|
||||
goto again
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i != read; {
|
||||
written, err := proxy.Listener.WriteToUDP(readBuf[i:read], clientAddr)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
i += written
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run starts forwarding the traffic using UDP.
|
||||
func (proxy *UDPProxy) Run() {
|
||||
proxy.connTrackTable = make(connTrackMap)
|
||||
readBuf := make([]byte, UDPBufSize)
|
||||
for {
|
||||
read, from, err := proxy.Listener.ReadFromUDP(readBuf)
|
||||
if err != nil {
|
||||
// NOTE: Apparently ReadFrom doesn't return
|
||||
// ECONNREFUSED like Read do (see comment in
|
||||
// UDPProxy.replyLoop)
|
||||
if !isClosedError(err) {
|
||||
fmt.Fprintf(proxy.LogWriter, "Stopping proxy on udp: %v\n", err)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
fromKey := newConnTrackKey(from)
|
||||
proxy.connTrackLock.Lock()
|
||||
proxyConn, hit := proxy.connTrackTable[*fromKey]
|
||||
if !hit {
|
||||
proxyConn, err = proxy.BackendDial()
|
||||
if err != nil {
|
||||
fmt.Fprintf(proxy.LogWriter, "Can't proxy a datagram to udp: %v\n", err)
|
||||
proxy.connTrackLock.Unlock()
|
||||
continue
|
||||
}
|
||||
proxy.connTrackTable[*fromKey] = proxyConn
|
||||
go proxy.replyLoop(proxyConn, from, fromKey)
|
||||
}
|
||||
proxy.connTrackLock.Unlock()
|
||||
for i := 0; i != read; {
|
||||
written, err := proxyConn.Write(readBuf[i:read])
|
||||
if err != nil {
|
||||
fmt.Fprintf(proxy.LogWriter, "Can't proxy a datagram to udp: %v\n", err)
|
||||
break
|
||||
}
|
||||
i += written
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close stops forwarding the traffic.
|
||||
func (proxy *UDPProxy) Close() {
|
||||
proxy.Listener.Close()
|
||||
proxy.connTrackLock.Lock()
|
||||
defer proxy.connTrackLock.Unlock()
|
||||
for _, conn := range proxy.connTrackTable {
|
||||
conn.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func isClosedError(err error) bool {
|
||||
/* This comparison is ugly, but unfortunately, net.go doesn't export errClosing.
|
||||
* See:
|
||||
* http://golang.org/src/pkg/net/net.go
|
||||
* https://code.google.com/p/go/issues/detail?id=4337
|
||||
* https://groups.google.com/forum/#!msg/golang-nuts/0_aaCvBmOcM/SptmDyX1XJMJ
|
||||
*/
|
||||
return strings.HasSuffix(err.Error(), "use of closed network connection")
|
||||
}
|
11
vendor/modules.txt
vendored
11
vendor/modules.txt
vendored
@ -383,7 +383,6 @@ github.com/docker/docker/api/types/volume
|
||||
github.com/docker/docker/client
|
||||
github.com/docker/docker/daemon/logger/jsonfilelog/jsonlog
|
||||
github.com/docker/docker/errdefs
|
||||
github.com/docker/docker/pkg/idtools
|
||||
github.com/docker/docker/pkg/jsonmessage
|
||||
github.com/docker/docker/pkg/longpath
|
||||
github.com/docker/docker/pkg/mount
|
||||
@ -774,7 +773,7 @@ github.com/rancher/wrangler-api/pkg/generated/controllers/rbac
|
||||
github.com/rancher/wrangler-api/pkg/generated/controllers/rbac/v1
|
||||
# github.com/robfig/cron v1.1.0
|
||||
github.com/robfig/cron
|
||||
# github.com/rootless-containers/rootlesskit v0.6.0
|
||||
# github.com/rootless-containers/rootlesskit v0.7.2
|
||||
github.com/rootless-containers/rootlesskit/pkg/api/client
|
||||
github.com/rootless-containers/rootlesskit/pkg/api/router
|
||||
github.com/rootless-containers/rootlesskit/pkg/child
|
||||
@ -787,8 +786,16 @@ github.com/rootless-containers/rootlesskit/pkg/network/iputils
|
||||
github.com/rootless-containers/rootlesskit/pkg/network/parentutils
|
||||
github.com/rootless-containers/rootlesskit/pkg/network/slirp4netns
|
||||
github.com/rootless-containers/rootlesskit/pkg/parent
|
||||
github.com/rootless-containers/rootlesskit/pkg/parent/idtools
|
||||
github.com/rootless-containers/rootlesskit/pkg/port
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/child
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/opaque
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/tcp
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy
|
||||
github.com/rootless-containers/rootlesskit/pkg/port/portutil
|
||||
# github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c
|
||||
github.com/rubiojr/go-vhd/vhd
|
||||
|
Loading…
Reference in New Issue
Block a user