1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Fix DNS entry update issue

When an update is done to the container resolv.conf file
and it was inheriting host entries, then we should not
re-read the host entries when the container leaves and
re-joins the endpoint.

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
This commit is contained in:
Jana Radhakrishnan 2015-05-15 21:01:53 +00:00
parent 4a3c7e1bb5
commit d96e94897e
2 changed files with 130 additions and 10 deletions

View file

@ -1,12 +1,15 @@
package libnetwork package libnetwork
import ( import (
"bytes"
"io/ioutil" "io/ioutil"
"os" "os"
"path"
"path/filepath" "path/filepath"
"sync" "sync"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/libnetwork/driverapi" "github.com/docker/libnetwork/driverapi"
"github.com/docker/libnetwork/netutils" "github.com/docker/libnetwork/netutils"
"github.com/docker/libnetwork/pkg/etchosts" "github.com/docker/libnetwork/pkg/etchosts"
@ -513,7 +516,7 @@ func (ep *endpoint) updateParentHosts() error {
return nil return nil
} }
func (ep *endpoint) setupDNS() error { func (ep *endpoint) updateDNS(resolvConf []byte) error {
ep.Lock() ep.Lock()
container := ep.container container := ep.container
network := ep.network network := ep.network
@ -523,6 +526,77 @@ func (ep *endpoint) setupDNS() error {
return ErrNoContainer return ErrNoContainer
} }
hashFile := container.config.resolvConfPath + ".hash"
oldHash, err := ioutil.ReadFile(hashFile)
if err != nil {
if !os.IsNotExist(err) {
return err
}
oldHash = []byte{}
}
resolvBytes, err := ioutil.ReadFile(container.config.resolvConfPath)
if err != nil {
if !os.IsNotExist(err) {
return err
}
}
curHash, err := ioutils.HashData(bytes.NewReader(resolvBytes))
if err != nil {
return err
}
if string(oldHash) != "" && curHash != string(oldHash) {
// Seems the user has changed the container resolv.conf since the last time
// we checked so return without doing anything.
return nil
}
// replace any localhost/127.* and remove IPv6 nameservers if IPv6 disabled.
resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6)
newHash, err := ioutils.HashData(bytes.NewReader(resolvConf))
if err != nil {
return err
}
// for atomic updates to these files, use temporary files with os.Rename:
dir := path.Dir(container.config.resolvConfPath)
tmpHashFile, err := ioutil.TempFile(dir, "hash")
if err != nil {
return err
}
tmpResolvFile, err := ioutil.TempFile(dir, "resolv")
if err != nil {
return err
}
// write the updates to the temp files
if err = ioutil.WriteFile(tmpHashFile.Name(), []byte(newHash), 0644); err != nil {
return err
}
if err = ioutil.WriteFile(tmpResolvFile.Name(), resolvConf, 0644); err != nil {
return err
}
// rename the temp files for atomic replace
if err = os.Rename(tmpHashFile.Name(), hashFile); err != nil {
return err
}
return os.Rename(tmpResolvFile.Name(), container.config.resolvConfPath)
}
func (ep *endpoint) setupDNS() error {
ep.Lock()
container := ep.container
ep.Unlock()
if container == nil {
return ErrNoContainer
}
if container.config.resolvConfPath == "" { if container.config.resolvConfPath == "" {
container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf" container.config.resolvConfPath = defaultPrefix + "/" + container.id + "/resolv.conf"
} }
@ -556,9 +630,7 @@ func (ep *endpoint) setupDNS() error {
return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList) return resolvconf.Build(container.config.resolvConfPath, dnsList, dnsSearchList)
} }
// replace any localhost/127.* but always discard IPv6 entries for now. return ep.updateDNS(resolvConf)
resolvConf, _ = resolvconf.FilterResolvDNS(resolvConf, network.enableIPv6)
return ioutil.WriteFile(ep.container.config.resolvConfPath, resolvConf, 0644)
} }
// EndpointOptionGeneric function returns an option setter for a Generic option defined // EndpointOptionGeneric function returns an option setter for a Generic option defined

View file

@ -1017,13 +1017,17 @@ func TestEnableIPv6(t *testing.T) {
} }
} }
func TestNoEnableIPv6(t *testing.T) { func TestResolvConf(t *testing.T) {
if !netutils.IsRunningInContainer() { if !netutils.IsRunningInContainer() {
defer netutils.SetupTestNetNS(t)() defer netutils.SetupTestNetNS(t)()
} }
tmpResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888") tmpResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\nnameserver 2001:4860:4860::8888")
expectedResolvConf := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n") expectedResolvConf1 := []byte("search pommesfrites.fr\nnameserver 12.34.56.78\n")
tmpResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\nnameserver 2001:4860:4860::8888")
expectedResolvConf2 := []byte("search pommesfrites.fr\nnameserver 112.34.56.78\n")
tmpResolvConf3 := []byte("search pommesfrites.fr\nnameserver 113.34.56.78\n")
//take a copy of resolv.conf for restoring after test completes //take a copy of resolv.conf for restoring after test completes
resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil { if err != nil {
@ -1046,7 +1050,7 @@ func TestNoEnableIPv6(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf, 0644); err != nil { if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf1, 0644); err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -1069,13 +1073,57 @@ func TestNoEnableIPv6(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
if !bytes.Equal(content, expectedResolvConf) { if !bytes.Equal(content, expectedResolvConf1) {
t.Fatalf("Expected %s, Got %s", string(expectedResolvConf), string(content)) t.Fatalf("Expected %s, Got %s", string(expectedResolvConf1), string(content))
} }
err = ep1.Leave(containerID)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := ioutil.WriteFile("/etc/resolv.conf", tmpResolvConf2, 0644); err != nil {
t.Fatal(err)
}
_, err = ep1.Join(containerID,
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
if err != nil {
t.Fatal(err)
}
content, err = ioutil.ReadFile(resolvConfPath)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(content, expectedResolvConf2) {
t.Fatalf("Expected %s, Got %s", string(expectedResolvConf2), string(content))
}
if err := ioutil.WriteFile(resolvConfPath, tmpResolvConf3, 0644); err != nil {
t.Fatal(err)
}
err = ep1.Leave(containerID)
if err != nil {
t.Fatal(err)
}
_, err = ep1.Join(containerID,
libnetwork.JoinOptionResolvConfPath(resolvConfPath))
if err != nil {
t.Fatal(err)
}
content, err = ioutil.ReadFile(resolvConfPath)
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(content, tmpResolvConf3) {
t.Fatalf("Expected %s, Got %s", string(tmpResolvConf3), string(content))
}
} }
var ( var (