mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #467 from thockin/14069-dns-options
Add DNS 'options' support
This commit is contained in:
commit
1e0b620ea7
3 changed files with 96 additions and 9 deletions
|
@ -30,6 +30,7 @@ var (
|
|||
nsIPv6Regexp = regexp.MustCompile(`(?m)^nameserver\s+` + ipv6Address + `\s*\n*`)
|
||||
nsRegexp = regexp.MustCompile(`^\s*nameserver\s*((` + ipv4Address + `)|(` + ipv6Address + `))\s*$`)
|
||||
searchRegexp = regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`)
|
||||
optionsRegexp = regexp.MustCompile(`^\s*options\s*(([^\s]+\s*)*)$`)
|
||||
)
|
||||
|
||||
var lastModified struct {
|
||||
|
@ -165,10 +166,25 @@ func GetSearchDomains(resolvConf []byte) []string {
|
|||
return domains
|
||||
}
|
||||
|
||||
// GetOptions returns options (if any) listed in /etc/resolv.conf
|
||||
// If more than one options line is encountered, only the contents of the last
|
||||
// one is returned.
|
||||
func GetOptions(resolvConf []byte) []string {
|
||||
options := []string{}
|
||||
for _, line := range getLines(resolvConf, []byte("#")) {
|
||||
match := optionsRegexp.FindSubmatch(line)
|
||||
if match == nil {
|
||||
continue
|
||||
}
|
||||
options = strings.Fields(string(match[1]))
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
// Build writes a configuration file to path containing a "nameserver" entry
|
||||
// for every element in dns, and a "search" entry for every element in
|
||||
// dnsSearch.
|
||||
func Build(path string, dns, dnsSearch []string) (string, error) {
|
||||
// for every element in dns, a "search" entry for every element in
|
||||
// dnsSearch, and an "options" entry for every element in dnsOptions.
|
||||
func Build(path string, dns, dnsSearch, dnsOptions []string) (string, error) {
|
||||
content := bytes.NewBuffer(nil)
|
||||
if len(dnsSearch) > 0 {
|
||||
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
||||
|
@ -182,6 +198,13 @@ func Build(path string, dns, dnsSearch []string) (string, error) {
|
|||
return "", err
|
||||
}
|
||||
}
|
||||
if len(dnsOptions) > 0 {
|
||||
if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
|
||||
if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hash, err := ioutils.HashData(bytes.NewReader(content.Bytes()))
|
||||
if err != nil {
|
||||
|
|
|
@ -98,6 +98,32 @@ nameserver 4.30.20.100`: {"foo.example.com", "example.com"},
|
|||
}
|
||||
}
|
||||
|
||||
func TestGetOptions(t *testing.T) {
|
||||
for resolv, result := range map[string][]string{
|
||||
`options opt1`: {"opt1"},
|
||||
`options opt1 # ignored`: {"opt1"},
|
||||
` options opt1 `: {"opt1"},
|
||||
` options opt1 # ignored`: {"opt1"},
|
||||
`options opt1 opt2 opt3`: {"opt1", "opt2", "opt3"},
|
||||
`options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"},
|
||||
` options opt1 opt2 opt3 `: {"opt1", "opt2", "opt3"},
|
||||
` options opt1 opt2 opt3 # ignored`: {"opt1", "opt2", "opt3"},
|
||||
``: {},
|
||||
`# ignored`: {},
|
||||
`nameserver 1.2.3.4`: {},
|
||||
`nameserver 1.2.3.4
|
||||
options opt1 opt2 opt3`: {"opt1", "opt2", "opt3"},
|
||||
`nameserver 1.2.3.4
|
||||
options opt1 opt2
|
||||
options opt3 opt4`: {"opt3", "opt4"},
|
||||
} {
|
||||
test := GetOptions([]byte(resolv))
|
||||
if !strSlicesEqual(test, result) {
|
||||
t.Fatalf("Wrong options string {%s} should be %v. Input: %s", test, result, resolv)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func strSlicesEqual(a, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
|
@ -119,7 +145,7 @@ func TestBuild(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"})
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{"opt1"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -129,7 +155,7 @@ func TestBuild(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||
}
|
||||
}
|
||||
|
@ -141,7 +167,7 @@ func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
|
|||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."})
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."}, []string{"opt1"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -151,7 +177,32 @@ func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||
}
|
||||
if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) {
|
||||
t.Fatalf("Expected to not find '%s' got '%s'", notExpected, content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWithNoOptions(t *testing.T) {
|
||||
file, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(file.Name())
|
||||
|
||||
_, err = Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
content, err := ioutil.ReadFile(file.Name())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if expected := "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"; !bytes.Contains(content, []byte(expected)) {
|
||||
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||
}
|
||||
if notExpected := "search ."; bytes.Contains(content, []byte(notExpected)) {
|
||||
|
|
|
@ -93,6 +93,7 @@ type resolvConfPathConfig struct {
|
|||
resolvConfHashFile string
|
||||
dnsList []string
|
||||
dnsSearchList []string
|
||||
dnsOptionsList []string
|
||||
}
|
||||
|
||||
type containerConfig struct {
|
||||
|
@ -406,17 +407,21 @@ func (sb *sandbox) setupDNS() error {
|
|||
}
|
||||
dnsList := resolvconf.GetNameservers(resolvConf)
|
||||
dnsSearchList := resolvconf.GetSearchDomains(resolvConf)
|
||||
dnsOptionsList := resolvconf.GetOptions(resolvConf)
|
||||
|
||||
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 {
|
||||
if len(sb.config.dnsList) > 0 || len(sb.config.dnsSearchList) > 0 || len(dnsOptionsList) > 0 {
|
||||
if len(sb.config.dnsList) > 0 {
|
||||
dnsList = sb.config.dnsList
|
||||
}
|
||||
if len(sb.config.dnsSearchList) > 0 {
|
||||
dnsSearchList = sb.config.dnsSearchList
|
||||
}
|
||||
if len(sb.config.dnsOptionsList) > 0 {
|
||||
dnsOptionsList = sb.config.dnsOptionsList
|
||||
}
|
||||
}
|
||||
|
||||
hash, err := resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList)
|
||||
hash, err := resolvconf.Build(sb.config.resolvConfPath, dnsList, dnsSearchList, dnsOptionsList)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -580,6 +585,14 @@ func OptionDNSSearch(search string) SandboxOption {
|
|||
}
|
||||
}
|
||||
|
||||
// OptionDNSOptions function returns an option setter for dns options entry option to
|
||||
// be passed to container Create method.
|
||||
func OptionDNSOptions(options string) SandboxOption {
|
||||
return func(sb *sandbox) {
|
||||
sb.config.dnsOptionsList = append(sb.config.dnsOptionsList, options)
|
||||
}
|
||||
}
|
||||
|
||||
// OptionUseDefaultSandbox function returns an option setter for using default sandbox to
|
||||
// be passed to container Create method.
|
||||
func OptionUseDefaultSandbox() SandboxOption {
|
||||
|
|
Loading…
Add table
Reference in a new issue