Merge pull request #9648 from estesp/9202-update-resolvconf

Update container resolv.conf when host network changes /etc/resolv.conf
This commit is contained in:
Alexander Morozov 2015-01-08 14:06:55 -08:00
commit ba9513ff3f
2 changed files with 96 additions and 2 deletions

View file

@ -5,13 +5,25 @@ import (
"io/ioutil"
"regexp"
"strings"
"sync"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/utils"
)
var (
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*(([0-9]+\.){3}([0-9]+))\s*$`)
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
defaultDns = []string{"8.8.8.8", "8.8.4.4"}
localHostRegexp = regexp.MustCompile(`(?m)^nameserver 127[^\n]+\n*`)
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*(([0-9]+\.){3}([0-9]+))\s*$`)
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
)
var lastModified struct {
sync.Mutex
sha256 string
contents []byte
}
func Get() ([]byte, error) {
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
@ -20,6 +32,57 @@ func Get() ([]byte, error) {
return resolv, nil
}
// Retrieves the host /etc/resolv.conf file, checks against the last hash
// and, if modified since last check, returns the bytes and new hash.
// This feature is used by the resolv.conf updater for containers
func GetIfChanged() ([]byte, string, error) {
lastModified.Lock()
defer lastModified.Unlock()
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
if err != nil {
return nil, "", err
}
newHash, err := utils.HashData(bytes.NewReader(resolv))
if err != nil {
return nil, "", err
}
if lastModified.sha256 != newHash {
lastModified.sha256 = newHash
lastModified.contents = resolv
return resolv, newHash, nil
}
// nothing changed, so return no data
return nil, "", nil
}
// retrieve the last used contents and hash of the host resolv.conf
// Used by containers updating on restart
func GetLastModified() ([]byte, string) {
lastModified.Lock()
defer lastModified.Unlock()
return lastModified.contents, lastModified.sha256
}
// RemoveReplaceLocalDns looks for localhost (127.*) entries in the provided
// resolv.conf, removing local nameserver entries, and, if the resulting
// cleaned config has no defined nameservers left, adds default DNS entries
// It also returns a boolean to notify the caller if changes were made at all
func RemoveReplaceLocalDns(resolvConf []byte) ([]byte, bool) {
changed := false
cleanedResolvConf := localHostRegexp.ReplaceAll(resolvConf, []byte{})
// if the resulting resolvConf is empty, use defaultDns
if !bytes.Contains(cleanedResolvConf, []byte("nameserver")) {
log.Infof("No non-localhost DNS nameservers are left in resolv.conf. Using default external servers : %v", defaultDns)
cleanedResolvConf = append(cleanedResolvConf, []byte("\nnameserver "+strings.Join(defaultDns, "\nnameserver "))...)
}
if !bytes.Equal(resolvConf, cleanedResolvConf) {
changed = true
}
return cleanedResolvConf, changed
}
// getLines parses input into lines and strips away comments.
func getLines(input []byte, commentMarker []byte) [][]byte {
lines := bytes.Split(input, []byte("\n"))

View file

@ -156,3 +156,34 @@ func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
t.Fatalf("Expected to not find '%s' got '%s'", notExpected, content)
}
}
func TestRemoveReplaceLocalDns(t *testing.T) {
ns0 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\n"
if result, _ := RemoveReplaceLocalDns([]byte(ns0)); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed No Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 := "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n"
if result, _ := RemoveReplaceLocalDns([]byte(ns1)); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 = "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n"
if result, _ := RemoveReplaceLocalDns([]byte(ns1)); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
ns1 = "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n"
if result, _ := RemoveReplaceLocalDns([]byte(ns1)); result != nil {
if ns0 != string(result) {
t.Fatalf("Failed Localhost: expected \n<%s> got \n<%s>", ns0, string(result))
}
}
}