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:
commit
ba9513ff3f
2 changed files with 96 additions and 2 deletions
|
@ -5,13 +5,25 @@ import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/docker/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*(([0-9]+\.){3}([0-9]+))\s*$`)
|
defaultDns = []string{"8.8.8.8", "8.8.4.4"}
|
||||||
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
|
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) {
|
func Get() ([]byte, error) {
|
||||||
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
resolv, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -20,6 +32,57 @@ func Get() ([]byte, error) {
|
||||||
return resolv, nil
|
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.
|
// getLines parses input into lines and strips away comments.
|
||||||
func getLines(input []byte, commentMarker []byte) [][]byte {
|
func getLines(input []byte, commentMarker []byte) [][]byte {
|
||||||
lines := bytes.Split(input, []byte("\n"))
|
lines := bytes.Split(input, []byte("\n"))
|
||||||
|
|
|
@ -156,3 +156,34 @@ func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
|
||||||
t.Fatalf("Expected to not find '%s' got '%s'", notExpected, content)
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue