Browse code

Merge pull request #8457 from jfrazelle/pr_8455

Check /etc/resolv.conf every time for 127.* content

Michael Crosby authored on 2014/10/09 08:21:14
Showing 3 changed files
... ...
@@ -1,6 +1,7 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
+	"bytes"
4 5
 	"encoding/json"
5 6
 	"errors"
6 7
 	"fmt"
... ...
@@ -917,22 +918,34 @@ func (container *Container) setupContainerDns() error {
917 917
 		return err
918 918
 	}
919 919
 
920
-	if config.NetworkMode != "host" && (len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0) {
921
-		var (
922
-			dns       = resolvconf.GetNameservers(resolvConf)
923
-			dnsSearch = resolvconf.GetSearchDomains(resolvConf)
924
-		)
925
-		if len(config.Dns) > 0 {
926
-			dns = config.Dns
927
-		} else if len(daemon.config.Dns) > 0 {
928
-			dns = daemon.config.Dns
920
+	if config.NetworkMode != "host" {
921
+		// check configurations for any container/daemon dns settings
922
+		if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 {
923
+			var (
924
+				dns       = resolvconf.GetNameservers(resolvConf)
925
+				dnsSearch = resolvconf.GetSearchDomains(resolvConf)
926
+			)
927
+			if len(config.Dns) > 0 {
928
+				dns = config.Dns
929
+			} else if len(daemon.config.Dns) > 0 {
930
+				dns = daemon.config.Dns
931
+			}
932
+			if len(config.DnsSearch) > 0 {
933
+				dnsSearch = config.DnsSearch
934
+			} else if len(daemon.config.DnsSearch) > 0 {
935
+				dnsSearch = daemon.config.DnsSearch
936
+			}
937
+			return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch)
929 938
 		}
930
-		if len(config.DnsSearch) > 0 {
931
-			dnsSearch = config.DnsSearch
932
-		} else if len(daemon.config.DnsSearch) > 0 {
933
-			dnsSearch = daemon.config.DnsSearch
939
+
940
+		// replace any localhost/127.* nameservers
941
+		resolvConf = utils.RemoveLocalDns(resolvConf)
942
+		// if the resulting resolvConf is empty, use DefaultDns
943
+		if !bytes.Contains(resolvConf, []byte("nameserver")) {
944
+			log.Infof("No non localhost DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v", DefaultDns)
945
+			// prefix the default dns options with nameserver
946
+			resolvConf = append(resolvConf, []byte("\nnameserver "+strings.Join(DefaultDns, "\nnameserver "))...)
934 947
 		}
935
-		return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch)
936 948
 	}
937 949
 	return ioutil.WriteFile(container.ResolvConfPath, resolvConf, 0644)
938 950
 }
... ...
@@ -1,7 +1,6 @@
1 1
 package daemon
2 2
 
3 3
 import (
4
-	"bytes"
5 4
 	"fmt"
6 5
 	"io"
7 6
 	"io/ioutil"
... ...
@@ -32,7 +31,6 @@ import (
32 32
 	"github.com/docker/docker/pkg/ioutils"
33 33
 	"github.com/docker/docker/pkg/log"
34 34
 	"github.com/docker/docker/pkg/namesgenerator"
35
-	"github.com/docker/docker/pkg/networkfs/resolvconf"
36 35
 	"github.com/docker/docker/pkg/parsers"
37 36
 	"github.com/docker/docker/pkg/parsers/kernel"
38 37
 	"github.com/docker/docker/pkg/sysinfo"
... ...
@@ -923,9 +921,6 @@ func NewDaemonFromDirectory(config *Config, eng *engine.Engine) (*Daemon, error)
923 923
 		eng:            eng,
924 924
 		trustStore:     t,
925 925
 	}
926
-	if err := daemon.checkLocaldns(); err != nil {
927
-		return nil, err
928
-	}
929 926
 	if err := daemon.restore(); err != nil {
930 927
 		return nil, err
931 928
 	}
... ...
@@ -1085,20 +1080,6 @@ func (daemon *Daemon) ContainerGraph() *graphdb.Database {
1085 1085
 	return daemon.containerGraph
1086 1086
 }
1087 1087
 
1088
-func (daemon *Daemon) checkLocaldns() error {
1089
-	resolvConf, err := resolvconf.Get()
1090
-	if err != nil {
1091
-		return err
1092
-	}
1093
-	resolvConf = utils.RemoveLocalDns(resolvConf)
1094
-
1095
-	if len(daemon.config.Dns) == 0 && !bytes.Contains(resolvConf, []byte("nameserver")) {
1096
-		log.Infof("No non localhost DNS resolver found in resolv.conf and containers can't use it. Using default external servers : %v", DefaultDns)
1097
-		daemon.config.Dns = DefaultDns
1098
-	}
1099
-	return nil
1100
-}
1101
-
1102 1088
 func (daemon *Daemon) ImageGetCached(imgID string, config *runconfig.Config) (*image.Image, error) {
1103 1089
 	// Retrieve all images
1104 1090
 	images, err := daemon.Graph().Map()
... ...
@@ -751,7 +751,7 @@ func TestRunEnvironment(t *testing.T) {
751 751
 	}
752 752
 	sort.Strings(goodEnv)
753 753
 	if len(goodEnv) != len(actualEnv) {
754
-		t.Fatalf("Wrong environment: should be %d variables, not: '%s'\n", len(goodEnv), strings.Join(actualEnv, ", "))
754
+		t.Fatalf("Wrong environment: should be %d variables, not: %q\n", len(goodEnv), strings.Join(actualEnv, ", "))
755 755
 	}
756 756
 	for i := range goodEnv {
757 757
 		if actualEnv[i] != goodEnv[i] {
... ...
@@ -1168,7 +1168,7 @@ func TestRunModeHostname(t *testing.T) {
1168 1168
 	}
1169 1169
 
1170 1170
 	if actual := strings.Trim(out, "\r\n"); actual != "testhostname" {
1171
-		t.Fatalf("expected 'testhostname', but says: '%s'", actual)
1171
+		t.Fatalf("expected 'testhostname', but says: %q", actual)
1172 1172
 	}
1173 1173
 
1174 1174
 	cmd = exec.Command(dockerBinary, "run", "--net=host", "busybox", "cat", "/etc/hostname")
... ...
@@ -1182,7 +1182,7 @@ func TestRunModeHostname(t *testing.T) {
1182 1182
 		t.Fatal(err)
1183 1183
 	}
1184 1184
 	if actual := strings.Trim(out, "\r\n"); actual != hostname {
1185
-		t.Fatalf("expected '%s', but says: '%s'", hostname, actual)
1185
+		t.Fatalf("expected %q, but says: '%s'", hostname, actual)
1186 1186
 	}
1187 1187
 
1188 1188
 	deleteAllContainers()
... ...
@@ -1196,7 +1196,7 @@ func TestRunRootWorkdir(t *testing.T) {
1196 1196
 		t.Fatal(s, err)
1197 1197
 	}
1198 1198
 	if s != "/\n" {
1199
-		t.Fatalf("pwd returned '%s' (expected /\\n)", s)
1199
+		t.Fatalf("pwd returned %q (expected /\\n)", s)
1200 1200
 	}
1201 1201
 
1202 1202
 	deleteAllContainers()
... ...
@@ -1266,20 +1266,39 @@ func TestRunWithVolumesIsRecursive(t *testing.T) {
1266 1266
 }
1267 1267
 
1268 1268
 func TestRunDnsDefaultOptions(t *testing.T) {
1269
+	// ci server has default resolv.conf
1270
+	// so rewrite it for the test
1271
+	origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1272
+	if os.IsNotExist(err) {
1273
+		t.Fatalf("/etc/resolv.conf does not exist")
1274
+	}
1275
+
1276
+	// test with file
1277
+	tmpResolvConf := []byte("nameserver 127.0.0.1")
1278
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
1279
+		t.Fatal(err)
1280
+	}
1281
+	// put the old resolvconf back
1282
+	defer func() {
1283
+		if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil {
1284
+			t.Fatal(err)
1285
+		}
1286
+	}()
1287
+
1269 1288
 	cmd := exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf")
1270 1289
 
1271 1290
 	actual, _, err := runCommandWithOutput(cmd)
1272 1291
 	if err != nil {
1273
-		t.Fatal(err, actual)
1292
+		t.Error(err, actual)
1293
+		return
1274 1294
 	}
1275 1295
 
1276
-	resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1277
-	if os.IsNotExist(err) {
1278
-		t.Fatalf("/etc/resolv.conf does not exist")
1279
-	}
1280
-
1281
-	if actual != string(resolvConf) {
1282
-		t.Fatalf("expected resolv.conf is not the same of actual")
1296
+	// check that the actual defaults are there
1297
+	// if we ever change the defaults from google dns, this will break
1298
+	expected := "\nnameserver 8.8.8.8\nnameserver 8.8.4.4"
1299
+	if actual != expected {
1300
+		t.Errorf("expected resolv.conf be: %q, but was: %q", expected, actual)
1301
+		return
1283 1302
 	}
1284 1303
 
1285 1304
 	deleteAllContainers()
... ...
@@ -1297,7 +1316,7 @@ func TestRunDnsOptions(t *testing.T) {
1297 1297
 
1298 1298
 	actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
1299 1299
 	if actual != "nameserver 127.0.0.1 search mydomain" {
1300
-		t.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: '%s'", actual)
1300
+		t.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual)
1301 1301
 	}
1302 1302
 
1303 1303
 	cmd = exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=.", "busybox", "cat", "/etc/resolv.conf")
... ...
@@ -1309,61 +1328,101 @@ func TestRunDnsOptions(t *testing.T) {
1309 1309
 
1310 1310
 	actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1)
1311 1311
 	if actual != "nameserver 127.0.0.1" {
1312
-		t.Fatalf("expected 'nameserver 127.0.0.1', but says: '%s'", actual)
1312
+		t.Fatalf("expected 'nameserver 127.0.0.1', but says: %q", actual)
1313 1313
 	}
1314 1314
 
1315 1315
 	logDone("run - dns options")
1316 1316
 }
1317 1317
 
1318 1318
 func TestRunDnsOptionsBasedOnHostResolvConf(t *testing.T) {
1319
-	resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1319
+	var out string
1320
+
1321
+	origResolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1320 1322
 	if os.IsNotExist(err) {
1321 1323
 		t.Fatalf("/etc/resolv.conf does not exist")
1322 1324
 	}
1323 1325
 
1324
-	hostNamservers := resolvconf.GetNameservers(resolvConf)
1325
-	hostSearch := resolvconf.GetSearchDomains(resolvConf)
1326
+	hostNamservers := resolvconf.GetNameservers(origResolvConf)
1327
+	hostSearch := resolvconf.GetSearchDomains(origResolvConf)
1326 1328
 
1327 1329
 	cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "busybox", "cat", "/etc/resolv.conf")
1328 1330
 
1329
-	out, _, err := runCommandWithOutput(cmd)
1330
-	if err != nil {
1331
+	if out, _, err = runCommandWithOutput(cmd); err != nil {
1331 1332
 		t.Fatal(err, out)
1332 1333
 	}
1333 1334
 
1334 1335
 	if actualNameservers := resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "127.0.0.1" {
1335
-		t.Fatalf("expected '127.0.0.1', but says: '%s'", string(actualNameservers[0]))
1336
+		t.Fatalf("expected '127.0.0.1', but says: %q", string(actualNameservers[0]))
1336 1337
 	}
1337 1338
 
1338 1339
 	actualSearch := resolvconf.GetSearchDomains([]byte(out))
1339 1340
 	if len(actualSearch) != len(hostSearch) {
1340
-		t.Fatalf("expected '%s' search domain(s), but it has: '%s'", len(hostSearch), len(actualSearch))
1341
+		t.Fatalf("expected %q search domain(s), but it has: '%s'", len(hostSearch), len(actualSearch))
1341 1342
 	}
1342 1343
 	for i := range actualSearch {
1343 1344
 		if actualSearch[i] != hostSearch[i] {
1344
-			t.Fatalf("expected '%s' domain, but says: '%s'", actualSearch[i], hostSearch[i])
1345
+			t.Fatalf("expected %q domain, but says: '%s'", actualSearch[i], hostSearch[i])
1345 1346
 		}
1346 1347
 	}
1347 1348
 
1348 1349
 	cmd = exec.Command(dockerBinary, "run", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
1349 1350
 
1350
-	out, _, err = runCommandWithOutput(cmd)
1351
-	if err != nil {
1351
+	if out, _, err = runCommandWithOutput(cmd); err != nil {
1352 1352
 		t.Fatal(err, out)
1353 1353
 	}
1354 1354
 
1355 1355
 	actualNameservers := resolvconf.GetNameservers([]byte(out))
1356 1356
 	if len(actualNameservers) != len(hostNamservers) {
1357
-		t.Fatalf("expected '%s' nameserver(s), but it has: '%s'", len(hostNamservers), len(actualNameservers))
1357
+		t.Fatalf("expected %q nameserver(s), but it has: '%s'", len(hostNamservers), len(actualNameservers))
1358 1358
 	}
1359 1359
 	for i := range actualNameservers {
1360 1360
 		if actualNameservers[i] != hostNamservers[i] {
1361
-			t.Fatalf("expected '%s' nameserver, but says: '%s'", actualNameservers[i], hostNamservers[i])
1361
+			t.Fatalf("expected %q nameserver, but says: '%s'", actualNameservers[i], hostNamservers[i])
1362 1362
 		}
1363 1363
 	}
1364 1364
 
1365 1365
 	if actualSearch = resolvconf.GetSearchDomains([]byte(out)); string(actualSearch[0]) != "mydomain" {
1366
-		t.Fatalf("expected 'mydomain', but says: '%s'", string(actualSearch[0]))
1366
+		t.Fatalf("expected 'mydomain', but says: %q", string(actualSearch[0]))
1367
+	}
1368
+
1369
+	// test with file
1370
+	tmpResolvConf := []byte("search example.com\nnameserver 12.34.56.78\nnameserver 127.0.0.1")
1371
+	if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil {
1372
+		t.Fatal(err)
1373
+	}
1374
+	// put the old resolvconf back
1375
+	defer func() {
1376
+		if err := ioutil.WriteFile("/etc/resolv.conf", origResolvConf, 0644); err != nil {
1377
+			t.Fatal(err)
1378
+		}
1379
+	}()
1380
+
1381
+	resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
1382
+	if os.IsNotExist(err) {
1383
+		t.Fatalf("/etc/resolv.conf does not exist")
1384
+	}
1385
+
1386
+	hostNamservers = resolvconf.GetNameservers(resolvConf)
1387
+	hostSearch = resolvconf.GetSearchDomains(resolvConf)
1388
+
1389
+	cmd = exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf")
1390
+
1391
+	if out, _, err = runCommandWithOutput(cmd); err != nil {
1392
+		t.Fatal(err, out)
1393
+	}
1394
+
1395
+	if actualNameservers = resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "12.34.56.78" || len(actualNameservers) != 1 {
1396
+		t.Fatalf("expected '12.34.56.78', but has: %v", actualNameservers)
1397
+	}
1398
+
1399
+	actualSearch = resolvconf.GetSearchDomains([]byte(out))
1400
+	if len(actualSearch) != len(hostSearch) {
1401
+		t.Fatalf("expected %q search domain(s), but it has: %q", len(hostSearch), len(actualSearch))
1402
+	}
1403
+	for i := range actualSearch {
1404
+		if actualSearch[i] != hostSearch[i] {
1405
+			t.Fatalf("expected %q domain, but says: '%s'", actualSearch[i], hostSearch[i])
1406
+		}
1367 1407
 	}
1368 1408
 
1369 1409
 	deleteAllContainers()
... ...
@@ -1382,7 +1441,7 @@ func TestRunAddHost(t *testing.T) {
1382 1382
 
1383 1383
 	actual := strings.Trim(out, "\r\n")
1384 1384
 	if actual != "86.75.30.9\textra" {
1385
-		t.Fatalf("expected '86.75.30.9\textra', but says: '%s'", actual)
1385
+		t.Fatalf("expected '86.75.30.9\textra', but says: %q", actual)
1386 1386
 	}
1387 1387
 
1388 1388
 	logDone("run - add-host option")
... ...
@@ -1989,7 +2048,7 @@ func TestRunCidFileCleanupIfEmpty(t *testing.T) {
1989 1989
 	}
1990 1990
 
1991 1991
 	if _, err := os.Stat(tmpCidFile); err == nil {
1992
-		t.Fatalf("empty CIDFile '%s' should've been deleted", tmpCidFile)
1992
+		t.Fatalf("empty CIDFile %q should've been deleted", tmpCidFile)
1993 1993
 	}
1994 1994
 	deleteAllContainers()
1995 1995
 	logDone("run - cleanup empty cidfile on fail")
... ...
@@ -2017,7 +2076,7 @@ func TestRunCidFileCheckIDLength(t *testing.T) {
2017 2017
 	}
2018 2018
 	cid := string(buffer)
2019 2019
 	if len(cid) != 64 {
2020
-		t.Fatalf("--cidfile should be a long id, not '%s'", id)
2020
+		t.Fatalf("--cidfile should be a long id, not %q", id)
2021 2021
 	}
2022 2022
 	if cid != id {
2023 2023
 		t.Fatalf("cid must be equal to %s, got %s", id, cid)