From a1a029f6d7f980960135c1346a1e9f7830692fac Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 5 May 2014 22:05:14 +0000 Subject: [PATCH 1/2] add etchosts Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- daemon/container.go | 24 ++------ pkg/networkfs/MAINTAINERS | 1 + pkg/networkfs/etchosts/etchosts.go | 34 ++++++++++++ pkg/networkfs/etchosts/etchosts_test.go | 74 +++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 pkg/networkfs/MAINTAINERS create mode 100644 pkg/networkfs/etchosts/etchosts.go create mode 100644 pkg/networkfs/etchosts/etchosts_test.go diff --git a/daemon/container.go b/daemon/container.go index 123eca0263..76bab3719b 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -22,6 +22,7 @@ import ( "github.com/dotcloud/docker/links" "github.com/dotcloud/docker/nat" "github.com/dotcloud/docker/pkg/label" + "github.com/dotcloud/docker/pkg/networkfs/etchosts" "github.com/dotcloud/docker/runconfig" "github.com/dotcloud/docker/utils" ) @@ -513,26 +514,11 @@ func (container *Container) buildHostname() { } } -func (container *Container) buildHostnameAndHostsFiles(IP string) { +func (container *Container) buildHostnameAndHostsFiles(IP string) error { container.buildHostname() - hostsContent := []byte(` -127.0.0.1 localhost -::1 localhost ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff00::0 ip6-mcastprefix -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -`) - container.HostsPath = path.Join(container.root, "hosts") - - if container.Config.Domainname != "" { - hostsContent = append([]byte(fmt.Sprintf("%s\t%s.%s %s\n", IP, container.Config.Hostname, container.Config.Domainname, container.Config.Hostname)), hostsContent...) - } else if !container.Config.NetworkDisabled { - hostsContent = append([]byte(fmt.Sprintf("%s\t%s\n", IP, container.Config.Hostname)), hostsContent...) - } - ioutil.WriteFile(container.HostsPath, hostsContent, 0644) + return etchosts.Build(container.HostsPath, IP, container.Config.Hostname, container.Config.Domainname) } func (container *Container) allocateNetwork() error { @@ -1072,12 +1058,12 @@ func (container *Container) initializeNetworking() error { container.Config.Domainname = nc.Config.Domainname } else if container.daemon.config.DisableNetwork { container.Config.NetworkDisabled = true - container.buildHostnameAndHostsFiles("127.0.1.1") + return container.buildHostnameAndHostsFiles("127.0.1.1") } else { if err := container.allocateNetwork(); err != nil { return err } - container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress) + return container.buildHostnameAndHostsFiles(container.NetworkSettings.IPAddress) } return nil } diff --git a/pkg/networkfs/MAINTAINERS b/pkg/networkfs/MAINTAINERS new file mode 100644 index 0000000000..ceeb0cfd18 --- /dev/null +++ b/pkg/networkfs/MAINTAINERS @@ -0,0 +1 @@ +Victor Vieux (@vieux) diff --git a/pkg/networkfs/etchosts/etchosts.go b/pkg/networkfs/etchosts/etchosts.go new file mode 100644 index 0000000000..169797071a --- /dev/null +++ b/pkg/networkfs/etchosts/etchosts.go @@ -0,0 +1,34 @@ +package etchosts + +import ( + "bytes" + "fmt" + "io/ioutil" +) + +var defaultContent = map[string]string{ + "localhost": "127.0.0.1", + "localhost ip6-localhost ip6-loopback": "::1", + "ip6-localnet": "fe00::0", + "ip6-mcastprefix": "ff00::0", + "ip6-allnodes": "ff02::1", + "ip6-allrouters": "ff02::2", +} + +func Build(path, IP, hostname, domainname string) error { + content := bytes.NewBuffer(nil) + if IP != "" { + if domainname != "" { + content.WriteString(fmt.Sprintf("%s\t%s.%s %s\n", IP, hostname, domainname, hostname)) + } else { + content.WriteString(fmt.Sprintf("%s\t%s\n", IP, hostname)) + } + } + + for hosts, ip := range defaultContent { + if _, err := content.WriteString(fmt.Sprintf("%s\t%s\n", ip, hosts)); err != nil { + return err + } + } + return ioutil.WriteFile(path, content.Bytes(), 0644) +} diff --git a/pkg/networkfs/etchosts/etchosts_test.go b/pkg/networkfs/etchosts/etchosts_test.go new file mode 100644 index 0000000000..da5662d64f --- /dev/null +++ b/pkg/networkfs/etchosts/etchosts_test.go @@ -0,0 +1,74 @@ +package etchosts + +import ( + "bytes" + "io/ioutil" + "os" + "testing" +) + +func TestBuildHostnameDomainname(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + + err = Build(file.Name(), "10.11.12.13", "testhostname", "testdomainname") + if err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := "10.11.12.13\ttesthostname.testdomainname testhostname\n"; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } +} + +func TestBuildHostname(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + + err = Build(file.Name(), "10.11.12.13", "testhostname", "") + if err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := "10.11.12.13\ttesthostname\n"; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } +} + +func TestBuildNoIP(t *testing.T) { + file, err := ioutil.TempFile("", "") + if err != nil { + t.Fatal(err) + } + defer os.Remove(file.Name()) + + err = Build(file.Name(), "", "testhostname", "") + if err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := ""; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } +} From 3744452ecf46351758478e99795e20b186a1bee4 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Mon, 5 May 2014 22:51:32 +0000 Subject: [PATCH 2/2] add resolvconf Docker-DCO-1.1-Signed-off-by: Victor Vieux (github: vieux) --- daemon/container.go | 23 +--- daemon/daemon.go | 3 +- daemon/networkdriver/bridge/driver.go | 14 ++- pkg/networkfs/resolvconf/resolvconf.go | 87 +++++++++++++ pkg/networkfs/resolvconf/resolvconf_test.go | 133 ++++++++++++++++++++ utils/utils.go | 54 +------- utils/utils_test.go | 103 --------------- 7 files changed, 237 insertions(+), 180 deletions(-) create mode 100644 pkg/networkfs/resolvconf/resolvconf.go create mode 100644 pkg/networkfs/resolvconf/resolvconf_test.go diff --git a/daemon/container.go b/daemon/container.go index 76bab3719b..68d2d2a62a 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -23,6 +23,7 @@ import ( "github.com/dotcloud/docker/nat" "github.com/dotcloud/docker/pkg/label" "github.com/dotcloud/docker/pkg/networkfs/etchosts" + "github.com/dotcloud/docker/pkg/networkfs/resolvconf" "github.com/dotcloud/docker/runconfig" "github.com/dotcloud/docker/utils" ) @@ -987,7 +988,7 @@ func (container *Container) setupContainerDns() error { return nil } - resolvConf, err := utils.GetResolvConf() + resolvConf, err := resolvconf.Get() if err != nil { return err } @@ -995,8 +996,8 @@ func (container *Container) setupContainerDns() error { // If custom dns exists, then create a resolv.conf for the container if len(config.Dns) > 0 || len(daemon.config.Dns) > 0 || len(config.DnsSearch) > 0 || len(daemon.config.DnsSearch) > 0 { var ( - dns = utils.GetNameservers(resolvConf) - dnsSearch = utils.GetSearchDomains(resolvConf) + dns = resolvconf.GetNameservers(resolvConf) + dnsSearch = resolvconf.GetSearchDomains(resolvConf) ) if len(config.Dns) > 0 { dns = config.Dns @@ -1009,21 +1010,7 @@ func (container *Container) setupContainerDns() error { dnsSearch = daemon.config.DnsSearch } container.ResolvConfPath = path.Join(container.root, "resolv.conf") - f, err := os.Create(container.ResolvConfPath) - if err != nil { - return err - } - defer f.Close() - for _, dns := range dns { - if _, err := f.Write([]byte("nameserver " + dns + "\n")); err != nil { - return err - } - } - if len(dnsSearch) > 0 { - if _, err := f.Write([]byte("search " + strings.Join(dnsSearch, " ") + "\n")); err != nil { - return err - } - } + return resolvconf.Build(container.ResolvConfPath, dns, dnsSearch) } else { container.ResolvConfPath = "/etc/resolv.conf" } diff --git a/daemon/daemon.go b/daemon/daemon.go index 22182f389f..00b6d9eee2 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -29,6 +29,7 @@ import ( "github.com/dotcloud/docker/pkg/graphdb" "github.com/dotcloud/docker/pkg/label" "github.com/dotcloud/docker/pkg/mount" + "github.com/dotcloud/docker/pkg/networkfs/resolvconf" "github.com/dotcloud/docker/pkg/selinux" "github.com/dotcloud/docker/pkg/sysinfo" "github.com/dotcloud/docker/runconfig" @@ -981,7 +982,7 @@ func (daemon *Daemon) SetServer(server Server) { } func (daemon *Daemon) checkLocaldns() error { - resolvConf, err := utils.GetResolvConf() + resolvConf, err := resolvconf.Get() if err != nil { return err } diff --git a/daemon/networkdriver/bridge/driver.go b/daemon/networkdriver/bridge/driver.go index 4828e3b9cf..c64aa423d1 100644 --- a/daemon/networkdriver/bridge/driver.go +++ b/daemon/networkdriver/bridge/driver.go @@ -2,6 +2,11 @@ package bridge import ( "fmt" + "io/ioutil" + "log" + "net" + "strings" + "github.com/dotcloud/docker/daemon/networkdriver" "github.com/dotcloud/docker/daemon/networkdriver/ipallocator" "github.com/dotcloud/docker/daemon/networkdriver/portallocator" @@ -9,11 +14,8 @@ import ( "github.com/dotcloud/docker/engine" "github.com/dotcloud/docker/pkg/iptables" "github.com/dotcloud/docker/pkg/netlink" + "github.com/dotcloud/docker/pkg/networkfs/resolvconf" "github.com/dotcloud/docker/utils" - "io/ioutil" - "log" - "net" - "strings" ) const ( @@ -222,13 +224,13 @@ func setupIPTables(addr net.Addr, icc bool) error { // If it can't find an address which doesn't conflict, it will return an error. func createBridge(bridgeIP string) error { nameservers := []string{} - resolvConf, _ := utils.GetResolvConf() + resolvConf, _ := resolvconf.Get() // we don't check for an error here, because we don't really care // if we can't read /etc/resolv.conf. So instead we skip the append // if resolvConf is nil. It either doesn't exist, or we can't read it // for some reason. if resolvConf != nil { - nameservers = append(nameservers, utils.GetNameserversAsCIDR(resolvConf)...) + nameservers = append(nameservers, resolvconf.GetNameserversAsCIDR(resolvConf)...) } var ifaceAddr string diff --git a/pkg/networkfs/resolvconf/resolvconf.go b/pkg/networkfs/resolvconf/resolvconf.go new file mode 100644 index 0000000000..d6854fb3b1 --- /dev/null +++ b/pkg/networkfs/resolvconf/resolvconf.go @@ -0,0 +1,87 @@ +package resolvconf + +import ( + "bytes" + "io/ioutil" + "regexp" + "strings" +) + +func Get() ([]byte, error) { + resolv, err := ioutil.ReadFile("/etc/resolv.conf") + if err != nil { + return nil, err + } + return resolv, nil +} + +// getLines parses input into lines and strips away comments. +func getLines(input []byte, commentMarker []byte) [][]byte { + lines := bytes.Split(input, []byte("\n")) + var output [][]byte + for _, currentLine := range lines { + var commentIndex = bytes.Index(currentLine, commentMarker) + if commentIndex == -1 { + output = append(output, currentLine) + } else { + output = append(output, currentLine[:commentIndex]) + } + } + return output +} + +// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf +func GetNameservers(resolvConf []byte) []string { + nameservers := []string{} + re := regexp.MustCompile(`^\s*nameserver\s*(([0-9]+\.){3}([0-9]+))\s*$`) + for _, line := range getLines(resolvConf, []byte("#")) { + var ns = re.FindSubmatch(line) + if len(ns) > 0 { + nameservers = append(nameservers, string(ns[1])) + } + } + return nameservers +} + +// GetNameserversAsCIDR returns nameservers (if any) listed in +// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32") +// This function's output is intended for net.ParseCIDR +func GetNameserversAsCIDR(resolvConf []byte) []string { + nameservers := []string{} + for _, nameserver := range GetNameservers(resolvConf) { + nameservers = append(nameservers, nameserver+"/32") + } + return nameservers +} + +// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf +// If more than one search line is encountered, only the contents of the last +// one is returned. +func GetSearchDomains(resolvConf []byte) []string { + re := regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`) + domains := []string{} + for _, line := range getLines(resolvConf, []byte("#")) { + match := re.FindSubmatch(line) + if match == nil { + continue + } + domains = strings.Fields(string(match[1])) + } + return domains +} + +func Build(path string, dns, dnsSearch []string) error { + content := bytes.NewBuffer(nil) + for _, dns := range dns { + if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil { + return err + } + } + if len(dnsSearch) > 0 { + if _, err := content.WriteString("search " + strings.Join(dnsSearch, " ") + "\n"); err != nil { + return err + } + } + + return ioutil.WriteFile(path, content.Bytes(), 0644) +} diff --git a/pkg/networkfs/resolvconf/resolvconf_test.go b/pkg/networkfs/resolvconf/resolvconf_test.go new file mode 100644 index 0000000000..fd20712376 --- /dev/null +++ b/pkg/networkfs/resolvconf/resolvconf_test.go @@ -0,0 +1,133 @@ +package resolvconf + +import ( + "bytes" + "io/ioutil" + "os" + "testing" +) + +func TestGet(t *testing.T) { + resolvConfUtils, err := Get() + if err != nil { + t.Fatal(err) + } + resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") + if err != nil { + t.Fatal(err) + } + if string(resolvConfUtils) != string(resolvConfSystem) { + t.Fatalf("/etc/resolv.conf and GetResolvConf have different content.") + } +} + +func TestGetNameservers(t *testing.T) { + for resolv, result := range map[string][]string{` +nameserver 1.2.3.4 +nameserver 40.3.200.10 +search example.com`: {"1.2.3.4", "40.3.200.10"}, + `search example.com`: {}, + `nameserver 1.2.3.4 +search example.com +nameserver 4.30.20.100`: {"1.2.3.4", "4.30.20.100"}, + ``: {}, + ` nameserver 1.2.3.4 `: {"1.2.3.4"}, + `search example.com +nameserver 1.2.3.4 +#nameserver 4.3.2.1`: {"1.2.3.4"}, + `search example.com +nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4"}, + } { + test := GetNameservers([]byte(resolv)) + if !strSlicesEqual(test, result) { + t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) + } + } +} + +func TestGetNameserversAsCIDR(t *testing.T) { + for resolv, result := range map[string][]string{` +nameserver 1.2.3.4 +nameserver 40.3.200.10 +search example.com`: {"1.2.3.4/32", "40.3.200.10/32"}, + `search example.com`: {}, + `nameserver 1.2.3.4 +search example.com +nameserver 4.30.20.100`: {"1.2.3.4/32", "4.30.20.100/32"}, + ``: {}, + ` nameserver 1.2.3.4 `: {"1.2.3.4/32"}, + `search example.com +nameserver 1.2.3.4 +#nameserver 4.3.2.1`: {"1.2.3.4/32"}, + `search example.com +nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4/32"}, + } { + test := GetNameserversAsCIDR([]byte(resolv)) + if !strSlicesEqual(test, result) { + t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) + } + } +} + +func TestGetSearchDomains(t *testing.T) { + for resolv, result := range map[string][]string{ + `search example.com`: {"example.com"}, + `search example.com # ignored`: {"example.com"}, + ` search example.com `: {"example.com"}, + ` search example.com # ignored`: {"example.com"}, + `search foo.example.com example.com`: {"foo.example.com", "example.com"}, + ` search foo.example.com example.com `: {"foo.example.com", "example.com"}, + ` search foo.example.com example.com # ignored`: {"foo.example.com", "example.com"}, + ``: {}, + `# ignored`: {}, + `nameserver 1.2.3.4 +search foo.example.com example.com`: {"foo.example.com", "example.com"}, + `nameserver 1.2.3.4 +search dup1.example.com dup2.example.com +search foo.example.com example.com`: {"foo.example.com", "example.com"}, + `nameserver 1.2.3.4 +search foo.example.com example.com +nameserver 4.30.20.100`: {"foo.example.com", "example.com"}, + } { + test := GetSearchDomains([]byte(resolv)) + if !strSlicesEqual(test, result) { + t.Fatalf("Wrong search domain string {%s} should be %v. Input: %s", test, result, resolv) + } + } +} + +func strSlicesEqual(a, b []string) bool { + if len(a) != len(b) { + return false + } + + for i, v := range a { + if v != b[i] { + return false + } + } + + return true +} + +func TestBuild(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"}) + if err != nil { + t.Fatal(err) + } + + content, err := ioutil.ReadFile(file.Name()) + if err != nil { + t.Fatal(err) + } + + if expected := "nameserver ns1\nnameserver ns2\nnameserver ns3\nsearch search1\n"; !bytes.Contains(content, []byte(expected)) { + t.Fatalf("Expected to find '%s' got '%s'", expected, content) + } +} diff --git a/utils/utils.go b/utils/utils.go index 066cfbac5a..4ef44b5617 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -9,7 +9,6 @@ import ( "encoding/json" "errors" "fmt" - "github.com/dotcloud/docker/dockerversion" "index/suffixarray" "io" "io/ioutil" @@ -23,6 +22,8 @@ import ( "strings" "sync" "time" + + "github.com/dotcloud/docker/dockerversion" ) type KeyValuePair struct { @@ -779,17 +780,6 @@ func IsGIT(str string) bool { return strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "github.com/") || strings.HasPrefix(str, "git@github.com:") || (strings.HasSuffix(str, ".git") && IsURL(str)) } -// GetResolvConf opens and read the content of /etc/resolv.conf. -// It returns it as byte slice. -func GetResolvConf() ([]byte, error) { - resolv, err := ioutil.ReadFile("/etc/resolv.conf") - if err != nil { - Errorf("Error openning resolv.conf: %s", err) - return nil, err - } - return resolv, nil -} - // CheckLocalDns looks into the /etc/resolv.conf, // it returns true if there is a local nameserver or if there is no nameserver. func CheckLocalDns(resolvConf []byte) bool { @@ -825,46 +815,6 @@ func GetLines(input []byte, commentMarker []byte) [][]byte { return output } -// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf -func GetNameservers(resolvConf []byte) []string { - nameservers := []string{} - re := regexp.MustCompile(`^\s*nameserver\s*(([0-9]+\.){3}([0-9]+))\s*$`) - for _, line := range GetLines(resolvConf, []byte("#")) { - var ns = re.FindSubmatch(line) - if len(ns) > 0 { - nameservers = append(nameservers, string(ns[1])) - } - } - return nameservers -} - -// GetNameserversAsCIDR returns nameservers (if any) listed in -// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32") -// This function's output is intended for net.ParseCIDR -func GetNameserversAsCIDR(resolvConf []byte) []string { - nameservers := []string{} - for _, nameserver := range GetNameservers(resolvConf) { - nameservers = append(nameservers, nameserver+"/32") - } - return nameservers -} - -// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf -// If more than one search line is encountered, only the contents of the last -// one is returned. -func GetSearchDomains(resolvConf []byte) []string { - re := regexp.MustCompile(`^\s*search\s*(([^\s]+\s*)*)$`) - domains := []string{} - for _, line := range GetLines(resolvConf, []byte("#")) { - match := re.FindSubmatch(line) - if match == nil { - continue - } - domains = strings.Fields(string(match[1])) - } - return domains -} - // FIXME: Change this not to receive default value as parameter func ParseHost(defaultHost string, defaultUnix, addr string) (string, error) { var ( diff --git a/utils/utils_test.go b/utils/utils_test.go index 501ae67c2c..ccd212202c 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -377,20 +377,6 @@ func TestParseRepositoryTag(t *testing.T) { } } -func TestGetResolvConf(t *testing.T) { - resolvConfUtils, err := GetResolvConf() - if err != nil { - t.Fatal(err) - } - resolvConfSystem, err := ioutil.ReadFile("/etc/resolv.conf") - if err != nil { - t.Fatal(err) - } - if string(resolvConfUtils) != string(resolvConfSystem) { - t.Fatalf("/etc/resolv.conf and GetResolvConf have different content.") - } -} - func TestCheckLocalDns(t *testing.T) { for resolv, result := range map[string]bool{`# Dynamic nameserver 10.0.2.3 @@ -464,95 +450,6 @@ func TestParsePortMapping(t *testing.T) { } } -func TestGetNameservers(t *testing.T) { - for resolv, result := range map[string][]string{` -nameserver 1.2.3.4 -nameserver 40.3.200.10 -search example.com`: {"1.2.3.4", "40.3.200.10"}, - `search example.com`: {}, - `nameserver 1.2.3.4 -search example.com -nameserver 4.30.20.100`: {"1.2.3.4", "4.30.20.100"}, - ``: {}, - ` nameserver 1.2.3.4 `: {"1.2.3.4"}, - `search example.com -nameserver 1.2.3.4 -#nameserver 4.3.2.1`: {"1.2.3.4"}, - `search example.com -nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4"}, - } { - test := GetNameservers([]byte(resolv)) - if !StrSlicesEqual(test, result) { - t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) - } - } -} - -func TestGetNameserversAsCIDR(t *testing.T) { - for resolv, result := range map[string][]string{` -nameserver 1.2.3.4 -nameserver 40.3.200.10 -search example.com`: {"1.2.3.4/32", "40.3.200.10/32"}, - `search example.com`: {}, - `nameserver 1.2.3.4 -search example.com -nameserver 4.30.20.100`: {"1.2.3.4/32", "4.30.20.100/32"}, - ``: {}, - ` nameserver 1.2.3.4 `: {"1.2.3.4/32"}, - `search example.com -nameserver 1.2.3.4 -#nameserver 4.3.2.1`: {"1.2.3.4/32"}, - `search example.com -nameserver 1.2.3.4 # not 4.3.2.1`: {"1.2.3.4/32"}, - } { - test := GetNameserversAsCIDR([]byte(resolv)) - if !StrSlicesEqual(test, result) { - t.Fatalf("Wrong nameserver string {%s} should be %v. Input: %s", test, result, resolv) - } - } -} - -func TestGetSearchDomains(t *testing.T) { - for resolv, result := range map[string][]string{ - `search example.com`: {"example.com"}, - `search example.com # ignored`: {"example.com"}, - ` search example.com `: {"example.com"}, - ` search example.com # ignored`: {"example.com"}, - `search foo.example.com example.com`: {"foo.example.com", "example.com"}, - ` search foo.example.com example.com `: {"foo.example.com", "example.com"}, - ` search foo.example.com example.com # ignored`: {"foo.example.com", "example.com"}, - ``: {}, - `# ignored`: {}, - `nameserver 1.2.3.4 -search foo.example.com example.com`: {"foo.example.com", "example.com"}, - `nameserver 1.2.3.4 -search dup1.example.com dup2.example.com -search foo.example.com example.com`: {"foo.example.com", "example.com"}, - `nameserver 1.2.3.4 -search foo.example.com example.com -nameserver 4.30.20.100`: {"foo.example.com", "example.com"}, - } { - test := GetSearchDomains([]byte(resolv)) - if !StrSlicesEqual(test, result) { - t.Fatalf("Wrong search domain string {%s} should be %v. Input: %s", test, result, resolv) - } - } -} - -func StrSlicesEqual(a, b []string) bool { - if len(a) != len(b) { - return false - } - - for i, v := range a { - if v != b[i] { - return false - } - } - - return true -} - func TestReplaceAndAppendEnvVars(t *testing.T) { var ( d = []string{"HOME=/"}