Signed-off-by: Tibor Vass <tibor@docker.com>
| ... | ... |
@@ -9,18 +9,13 @@ import ( |
| 9 | 9 |
"strings" |
| 10 | 10 |
|
| 11 | 11 |
"github.com/docker/docker/daemon/config" |
| 12 |
- "github.com/docker/docker/internal/procfs" |
|
| 13 | 12 |
"github.com/docker/docker/pkg/fileutils" |
| 14 | 13 |
"github.com/docker/docker/pkg/mount" |
| 14 |
+ "github.com/docker/libnetwork/resolvconf" |
|
| 15 | 15 |
"github.com/pkg/errors" |
| 16 | 16 |
"github.com/sirupsen/logrus" |
| 17 | 17 |
) |
| 18 | 18 |
|
| 19 |
-const ( |
|
| 20 |
- defaultResolvConf = "/etc/resolv.conf" |
|
| 21 |
- alternateResolvConf = "/run/systemd/resolve/resolv.conf" |
|
| 22 |
-) |
|
| 23 |
- |
|
| 24 | 19 |
// On Linux, plugins use a static path for storing execution state, |
| 25 | 20 |
// instead of deriving path from daemon's exec-root. This is because |
| 26 | 21 |
// plugin socket files are created here and they cannot exceed max |
| ... | ... |
@@ -148,20 +143,5 @@ func setupResolvConf(config *config.Config) {
|
| 148 | 148 |
if config.ResolvConf != "" {
|
| 149 | 149 |
return |
| 150 | 150 |
} |
| 151 |
- |
|
| 152 |
- config.ResolvConf = defaultResolvConf |
|
| 153 |
- pids, err := procfs.PidOf("systemd-resolved")
|
|
| 154 |
- if err != nil {
|
|
| 155 |
- logrus.Errorf("unable to check systemd-resolved status: %s", err)
|
|
| 156 |
- return |
|
| 157 |
- } |
|
| 158 |
- if len(pids) > 0 && pids[0] > 0 {
|
|
| 159 |
- _, err := os.Stat(alternateResolvConf) |
|
| 160 |
- if err == nil {
|
|
| 161 |
- logrus.Infof("systemd-resolved is running, so using resolvconf: %s", alternateResolvConf)
|
|
| 162 |
- config.ResolvConf = alternateResolvConf |
|
| 163 |
- return |
|
| 164 |
- } |
|
| 165 |
- logrus.Infof("systemd-resolved is running, but %s is not present, fallback to %s", alternateResolvConf, defaultResolvConf)
|
|
| 166 |
- } |
|
| 151 |
+ config.ResolvConf = resolvconf.Path() |
|
| 167 | 152 |
} |
| 168 | 153 |
deleted file mode 100644 |
| ... | ... |
@@ -1,105 +0,0 @@ |
| 1 |
-package procfs |
|
| 2 |
- |
|
| 3 |
-/* |
|
| 4 |
-Copyright 2015 The Kubernetes Authors. |
|
| 5 |
- |
|
| 6 |
-Licensed under the Apache License, Version 2.0 (the "License"); |
|
| 7 |
-you may not use this file except in compliance with the License. |
|
| 8 |
-You may obtain a copy of the License at |
|
| 9 |
- |
|
| 10 |
-http://www.apache.org/licenses/LICENSE-2.0 |
|
| 11 |
- |
|
| 12 |
-Unless required by applicable law or agreed to in writing, software |
|
| 13 |
-distributed under the License is distributed on an "AS IS" BASIS, |
|
| 14 |
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
| 15 |
-See the License for the specific language governing permissions and |
|
| 16 |
-limitations under the License. |
|
| 17 |
-*/ |
|
| 18 |
- |
|
| 19 |
-import ( |
|
| 20 |
- "bytes" |
|
| 21 |
- "fmt" |
|
| 22 |
- "io" |
|
| 23 |
- "io/ioutil" |
|
| 24 |
- "os" |
|
| 25 |
- "path/filepath" |
|
| 26 |
- "regexp" |
|
| 27 |
- "strconv" |
|
| 28 |
- "strings" |
|
| 29 |
- "unicode" |
|
| 30 |
- |
|
| 31 |
- "github.com/sirupsen/logrus" |
|
| 32 |
-) |
|
| 33 |
- |
|
| 34 |
-// PidOf finds process(es) with a specified name (regexp match) |
|
| 35 |
-// and return their pid(s) |
|
| 36 |
-func PidOf(name string) ([]int, error) {
|
|
| 37 |
- if len(name) == 0 {
|
|
| 38 |
- return []int{}, fmt.Errorf("name should not be empty")
|
|
| 39 |
- } |
|
| 40 |
- re, err := regexp.Compile("(^|/)" + name + "$")
|
|
| 41 |
- if err != nil {
|
|
| 42 |
- return []int{}, err
|
|
| 43 |
- } |
|
| 44 |
- return getPids(re), nil |
|
| 45 |
-} |
|
| 46 |
- |
|
| 47 |
-func getPids(re *regexp.Regexp) []int {
|
|
| 48 |
- pids := []int{}
|
|
| 49 |
- |
|
| 50 |
- dirFD, err := os.Open("/proc")
|
|
| 51 |
- if err != nil {
|
|
| 52 |
- return nil |
|
| 53 |
- } |
|
| 54 |
- defer dirFD.Close() |
|
| 55 |
- |
|
| 56 |
- for {
|
|
| 57 |
- // Read a small number at a time in case there are many entries, we don't want to |
|
| 58 |
- // allocate a lot here. |
|
| 59 |
- ls, err := dirFD.Readdir(10) |
|
| 60 |
- if err == io.EOF {
|
|
| 61 |
- break |
|
| 62 |
- } |
|
| 63 |
- if err != nil {
|
|
| 64 |
- return nil |
|
| 65 |
- } |
|
| 66 |
- |
|
| 67 |
- for _, entry := range ls {
|
|
| 68 |
- if !entry.IsDir() {
|
|
| 69 |
- continue |
|
| 70 |
- } |
|
| 71 |
- |
|
| 72 |
- // If the directory is not a number (i.e. not a PID), skip it |
|
| 73 |
- pid, err := strconv.Atoi(entry.Name()) |
|
| 74 |
- if err != nil {
|
|
| 75 |
- continue |
|
| 76 |
- } |
|
| 77 |
- |
|
| 78 |
- cmdline, err := ioutil.ReadFile(filepath.Join("/proc", entry.Name(), "cmdline"))
|
|
| 79 |
- if err != nil {
|
|
| 80 |
- logrus.Infof("Error reading file %s: %+v", filepath.Join("/proc", entry.Name(), "cmdline"), err)
|
|
| 81 |
- continue |
|
| 82 |
- } |
|
| 83 |
- |
|
| 84 |
- // The bytes we read have '\0' as a separator for the command line |
|
| 85 |
- parts := bytes.SplitN(cmdline, []byte{0}, 2)
|
|
| 86 |
- if len(parts) == 0 {
|
|
| 87 |
- continue |
|
| 88 |
- } |
|
| 89 |
- // Split the command line itself we are interested in just the first part |
|
| 90 |
- exe := strings.FieldsFunc(string(parts[0]), func(c rune) bool {
|
|
| 91 |
- return unicode.IsSpace(c) || c == ':' |
|
| 92 |
- }) |
|
| 93 |
- if len(exe) == 0 {
|
|
| 94 |
- continue |
|
| 95 |
- } |
|
| 96 |
- // Check if the name of the executable is what we are looking for |
|
| 97 |
- if re.MatchString(exe[0]) {
|
|
| 98 |
- // Grab the PID from the directory path |
|
| 99 |
- pids = append(pids, pid) |
|
| 100 |
- } |
|
| 101 |
- } |
|
| 102 |
- } |
|
| 103 |
- |
|
| 104 |
- return pids |
|
| 105 |
-} |
| 106 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,36 +0,0 @@ |
| 1 |
-package procfs |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "os" |
|
| 5 |
- "path/filepath" |
|
| 6 |
- "regexp" |
|
| 7 |
- "runtime" |
|
| 8 |
- "testing" |
|
| 9 |
- |
|
| 10 |
- "gotest.tools/assert" |
|
| 11 |
-) |
|
| 12 |
- |
|
| 13 |
-func TestPidOf(t *testing.T) {
|
|
| 14 |
- pids, err := PidOf(filepath.Base(os.Args[0])) |
|
| 15 |
- assert.NilError(t, err) |
|
| 16 |
- assert.Check(t, len(pids) == 1) |
|
| 17 |
- assert.DeepEqual(t, pids[0], os.Getpid()) |
|
| 18 |
-} |
|
| 19 |
- |
|
| 20 |
-func BenchmarkGetPids(b *testing.B) {
|
|
| 21 |
- if runtime.GOOS == "darwin" || runtime.GOOS == "windows" {
|
|
| 22 |
- b.Skipf("not supported on GOOS=%s", runtime.GOOS)
|
|
| 23 |
- } |
|
| 24 |
- |
|
| 25 |
- re, err := regexp.Compile("(^|/)" + filepath.Base(os.Args[0]) + "$")
|
|
| 26 |
- assert.Check(b, err == nil) |
|
| 27 |
- |
|
| 28 |
- for i := 0; i < b.N; i++ {
|
|
| 29 |
- pids := getPids(re) |
|
| 30 |
- |
|
| 31 |
- b.StopTimer() |
|
| 32 |
- assert.Check(b, len(pids) > 0) |
|
| 33 |
- assert.Check(b, pids[0] == os.Getpid()) |
|
| 34 |
- b.StartTimer() |
|
| 35 |
- } |
|
| 36 |
-} |
| ... | ... |
@@ -27,7 +27,7 @@ github.com/imdario/mergo 7c29201646fa3de8506f70121347 |
| 27 | 27 |
golang.org/x/sync e225da77a7e68af35c70ccbf71af2b83e6acac3c |
| 28 | 28 |
|
| 29 | 29 |
# buildkit |
| 30 |
-github.com/moby/buildkit 37d53758a68d9f5cede1806dbb2da7c3caa8d5bc |
|
| 30 |
+github.com/moby/buildkit 1f89ec125f84c097bdf3a063be622c4238dba5f8 |
|
| 31 | 31 |
github.com/tonistiigi/fsutil 3bbb99cdbd76619ab717299830c60f6f2a533a6b |
| 32 | 32 |
github.com/grpc-ecosystem/grpc-opentracing 8e809c8a86450a29b90dcc9efbf062d0fe6d9746 |
| 33 | 33 |
github.com/opentracing/opentracing-go 1361b9cd60be79c4c3a7fa9841b3c132e40066a7 |
| ... | ... |
@@ -39,7 +39,7 @@ github.com/gofrs/flock 7f43ea2e6a643ad441fc12d0ecc0 |
| 39 | 39 |
# libnetwork |
| 40 | 40 |
|
| 41 | 41 |
# When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/install/proxy.installer accordingly |
| 42 |
-github.com/docker/libnetwork 5ac07abef4eee176423fdc1b870d435258e2d381 |
|
| 42 |
+github.com/docker/libnetwork fc5a7d91d54cc98f64fc28f9e288b46a0bee756c |
|
| 43 | 43 |
github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9 |
| 44 | 44 |
github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80 |
| 45 | 45 |
github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec |
| ... | ... |
@@ -339,7 +339,6 @@ func (c *controller) clusterAgentInit() {
|
| 339 | 339 |
} |
| 340 | 340 |
} |
| 341 | 341 |
case cluster.EventNodeLeave: |
| 342 |
- keysAvailable = false |
|
| 343 | 342 |
c.agentOperationStart() |
| 344 | 343 |
c.Lock() |
| 345 | 344 |
c.keys = nil |
| ... | ... |
@@ -706,11 +705,17 @@ const overlayDSROptionString = "dsr" |
| 706 | 706 |
// NewNetwork creates a new network of the specified network type. The options |
| 707 | 707 |
// are network specific and modeled in a generic way. |
| 708 | 708 |
func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) {
|
| 709 |
+ var ( |
|
| 710 |
+ cap *driverapi.Capability |
|
| 711 |
+ err error |
|
| 712 |
+ t *network |
|
| 713 |
+ ) |
|
| 714 |
+ |
|
| 709 | 715 |
if id != "" {
|
| 710 | 716 |
c.networkLocker.Lock(id) |
| 711 | 717 |
defer c.networkLocker.Unlock(id) |
| 712 | 718 |
|
| 713 |
- if _, err := c.NetworkByID(id); err == nil {
|
|
| 719 |
+ if _, err = c.NetworkByID(id); err == nil {
|
|
| 714 | 720 |
return nil, NetworkNameError(id) |
| 715 | 721 |
} |
| 716 | 722 |
} |
| ... | ... |
@@ -739,15 +744,10 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... |
| 739 | 739 |
} |
| 740 | 740 |
|
| 741 | 741 |
network.processOptions(options...) |
| 742 |
- if err := network.validateConfiguration(); err != nil {
|
|
| 742 |
+ if err = network.validateConfiguration(); err != nil {
|
|
| 743 | 743 |
return nil, err |
| 744 | 744 |
} |
| 745 | 745 |
|
| 746 |
- var ( |
|
| 747 |
- cap *driverapi.Capability |
|
| 748 |
- err error |
|
| 749 |
- ) |
|
| 750 |
- |
|
| 751 | 746 |
// Reset network types, force local scope and skip allocation and |
| 752 | 747 |
// plumbing for configuration networks. Reset of the config-only |
| 753 | 748 |
// network drivers is needed so that this special network is not |
| ... | ... |
@@ -794,11 +794,11 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ... |
| 794 | 794 |
// From this point on, we need the network specific configuration, |
| 795 | 795 |
// which may come from a configuration-only network |
| 796 | 796 |
if network.configFrom != "" {
|
| 797 |
- t, err := c.getConfigNetwork(network.configFrom) |
|
| 797 |
+ t, err = c.getConfigNetwork(network.configFrom) |
|
| 798 | 798 |
if err != nil {
|
| 799 | 799 |
return nil, types.NotFoundErrorf("configuration network %q does not exist", network.configFrom)
|
| 800 | 800 |
} |
| 801 |
- if err := t.applyConfigurationTo(network); err != nil {
|
|
| 801 |
+ if err = t.applyConfigurationTo(network); err != nil {
|
|
| 802 | 802 |
return nil, types.InternalErrorf("Failed to apply configuration: %v", err)
|
| 803 | 803 |
} |
| 804 | 804 |
defer func() {
|
| ... | ... |
@@ -15,11 +15,45 @@ import ( |
| 15 | 15 |
) |
| 16 | 16 |
|
| 17 | 17 |
const ( |
| 18 |
- // DefaultResolvConf points to the default file used for dns configuration on a linux machine |
|
| 19 |
- DefaultResolvConf = "/etc/resolv.conf" |
|
| 18 |
+ // defaultPath is the default path to the resolv.conf that contains information to resolve DNS. See Path(). |
|
| 19 |
+ defaultPath = "/etc/resolv.conf" |
|
| 20 |
+ // alternatePath is a path different from defaultPath, that may be used to resolve DNS. See Path(). |
|
| 21 |
+ alternatePath = "/run/systemd/resolve/resolv.conf" |
|
| 20 | 22 |
) |
| 21 | 23 |
|
| 22 | 24 |
var ( |
| 25 |
+ detectSystemdResolvConfOnce sync.Once |
|
| 26 |
+ pathAfterSystemdDetection = defaultPath |
|
| 27 |
+) |
|
| 28 |
+ |
|
| 29 |
+// Path returns the path to the resolv.conf file that libnetwork should use. |
|
| 30 |
+// |
|
| 31 |
+// When /etc/resolv.conf contains 127.0.0.53 as the only nameserver, then |
|
| 32 |
+// it is assumed systemd-resolved manages DNS. Because inside the container 127.0.0.53 |
|
| 33 |
+// is not a valid DNS server, Path() returns /run/systemd/resolve/resolv.conf |
|
| 34 |
+// which is the resolv.conf that systemd-resolved generates and manages. |
|
| 35 |
+// Otherwise Path() returns /etc/resolv.conf. |
|
| 36 |
+// |
|
| 37 |
+// Errors are silenced as they will inevitably resurface at future open/read calls. |
|
| 38 |
+// |
|
| 39 |
+// More information at https://www.freedesktop.org/software/systemd/man/systemd-resolved.service.html#/etc/resolv.conf |
|
| 40 |
+func Path() string {
|
|
| 41 |
+ detectSystemdResolvConfOnce.Do(func() {
|
|
| 42 |
+ candidateResolvConf, err := ioutil.ReadFile(defaultPath) |
|
| 43 |
+ if err != nil {
|
|
| 44 |
+ // silencing error as it will resurface at next calls trying to read defaultPath |
|
| 45 |
+ return |
|
| 46 |
+ } |
|
| 47 |
+ ns := GetNameservers(candidateResolvConf, types.IP) |
|
| 48 |
+ if len(ns) == 1 && ns[0] == "127.0.0.53" {
|
|
| 49 |
+ pathAfterSystemdDetection = alternatePath |
|
| 50 |
+ logrus.Infof("detected 127.0.0.53 nameserver, assuming systemd-resolved, so using resolv.conf: %s", alternatePath)
|
|
| 51 |
+ } |
|
| 52 |
+ }) |
|
| 53 |
+ return pathAfterSystemdDetection |
|
| 54 |
+} |
|
| 55 |
+ |
|
| 56 |
+var ( |
|
| 23 | 57 |
// Note: the default IPv4 & IPv6 resolvers are set to Google's Public DNS |
| 24 | 58 |
defaultIPv4Dns = []string{"nameserver 8.8.8.8", "nameserver 8.8.4.4"}
|
| 25 | 59 |
defaultIPv6Dns = []string{"nameserver 2001:4860:4860::8888", "nameserver 2001:4860:4860::8844"}
|
| ... | ... |
@@ -55,7 +89,7 @@ type File struct {
|
| 55 | 55 |
|
| 56 | 56 |
// Get returns the contents of /etc/resolv.conf and its hash |
| 57 | 57 |
func Get() (*File, error) {
|
| 58 |
- return GetSpecific(DefaultResolvConf) |
|
| 58 |
+ return GetSpecific(Path()) |
|
| 59 | 59 |
} |
| 60 | 60 |
|
| 61 | 61 |
// GetSpecific returns the contents of the user specified resolv.conf file and its hash |
| ... | ... |
@@ -78,7 +112,7 @@ func GetIfChanged() (*File, error) {
|
| 78 | 78 |
lastModified.Lock() |
| 79 | 79 |
defer lastModified.Unlock() |
| 80 | 80 |
|
| 81 |
- resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
|
| 81 |
+ resolv, err := ioutil.ReadFile(Path()) |
|
| 82 | 82 |
if err != nil {
|
| 83 | 83 |
return nil, err |
| 84 | 84 |
} |
| ... | ... |
@@ -213,8 +213,8 @@ func (sb *sandbox) setupDNS() error {
|
| 213 | 213 |
|
| 214 | 214 |
originResolvConfPath := sb.config.originResolvConfPath |
| 215 | 215 |
if originResolvConfPath == "" {
|
| 216 |
- // if not specified fallback to default /etc/resolv.conf |
|
| 217 |
- originResolvConfPath = resolvconf.DefaultResolvConf |
|
| 216 |
+ // fallback if not specified |
|
| 217 |
+ originResolvConfPath = resolvconf.Path() |
|
| 218 | 218 |
} |
| 219 | 219 |
currRC, err := resolvconf.GetSpecific(originResolvConfPath) |
| 220 | 220 |
if err != nil {
|
| ... | ... |
@@ -29,7 +29,7 @@ func GetResolvConf(ctx context.Context, stateDir string) (string, error) {
|
| 29 | 29 |
generate = true |
| 30 | 30 |
} |
| 31 | 31 |
if !generate {
|
| 32 |
- fiMain, err := os.Stat("/etc/resolv.conf")
|
|
| 32 |
+ fiMain, err := os.Stat(resolvconf.Path()) |
|
| 33 | 33 |
if err != nil {
|
| 34 | 34 |
if !os.IsNotExist(err) {
|
| 35 | 35 |
return nil, err |