mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Relax dns search to accept empty domain
In that case /etc/resolv.conf will be generated with no search option. Usage: --dns-search=. Docker-DCO-1.1-Signed-off-by: Fabio Falci <fabiofalci@gmail.com> (github: fabiofalci)
This commit is contained in:
parent
44d737707c
commit
804b00cd7d
7 changed files with 158 additions and 11 deletions
|
@ -52,7 +52,7 @@ func main() {
|
|||
flSocketGroup = flag.String([]string{"G", "-group"}, "docker", "Group to assign the unix socket specified by -H when running in daemon mode\nuse '' (the empty string) to disable setting of a group")
|
||||
flEnableCors = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
|
||||
flDns = opts.NewListOpts(opts.ValidateIp4Address)
|
||||
flDnsSearch = opts.NewListOpts(opts.ValidateDomain)
|
||||
flDnsSearch = opts.NewListOpts(opts.ValidateDnsSearch)
|
||||
flEnableIptables = flag.Bool([]string{"#iptables", "-iptables"}, true, "Enable Docker's addition of iptables rules")
|
||||
flEnableIpForward = flag.Bool([]string{"#ip-forward", "-ip-forward"}, true, "Enable net.ipv4.ip_forward")
|
||||
flDefaultIp = flag.String([]string{"#ip", "-ip"}, "0.0.0.0", "Default IP address to use when binding container ports")
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
|
@ -10,6 +11,8 @@ import (
|
|||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
|
||||
)
|
||||
|
||||
// "test123" should be printed by docker run
|
||||
|
@ -983,3 +986,109 @@ func TestDisallowBindMountingRootToRoot(t *testing.T) {
|
|||
|
||||
logDone("run - bind mount /:/ as volume should fail")
|
||||
}
|
||||
|
||||
func TestDnsDefaultOptions(t *testing.T) {
|
||||
cmd := exec.Command(dockerBinary, "run", "busybox", "cat", "/etc/resolv.conf")
|
||||
|
||||
actual, _, err := runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, actual)
|
||||
}
|
||||
|
||||
resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if os.IsNotExist(err) {
|
||||
t.Fatalf("/etc/resolv.conf does not exist")
|
||||
}
|
||||
|
||||
if actual != string(resolvConf) {
|
||||
t.Fatalf("expected resolv.conf is not the same of actual")
|
||||
}
|
||||
|
||||
deleteAllContainers()
|
||||
|
||||
logDone("run - dns default options")
|
||||
}
|
||||
|
||||
func TestDnsOptions(t *testing.T) {
|
||||
cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
|
||||
|
||||
out, _, err := runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
|
||||
if actual != "nameserver 127.0.0.1 search mydomain" {
|
||||
t.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: '%s'", actual)
|
||||
}
|
||||
|
||||
cmd = exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "--dns-search=.", "busybox", "cat", "/etc/resolv.conf")
|
||||
|
||||
out, _, err = runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1)
|
||||
if actual != "nameserver 127.0.0.1" {
|
||||
t.Fatalf("expected 'nameserver 127.0.0.1', but says: '%s'", actual)
|
||||
}
|
||||
|
||||
logDone("run - dns options")
|
||||
}
|
||||
|
||||
func TestDnsOptionsBasedOnHostResolvConf(t *testing.T) {
|
||||
resolvConf, err := ioutil.ReadFile("/etc/resolv.conf")
|
||||
if os.IsNotExist(err) {
|
||||
t.Fatalf("/etc/resolv.conf does not exist")
|
||||
}
|
||||
|
||||
hostNamservers := resolvconf.GetNameservers(resolvConf)
|
||||
hostSearch := resolvconf.GetSearchDomains(resolvConf)
|
||||
|
||||
cmd := exec.Command(dockerBinary, "run", "--dns=127.0.0.1", "busybox", "cat", "/etc/resolv.conf")
|
||||
|
||||
out, _, err := runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
if actualNameservers := resolvconf.GetNameservers([]byte(out)); string(actualNameservers[0]) != "127.0.0.1" {
|
||||
t.Fatalf("expected '127.0.0.1', but says: '%s'", string(actualNameservers[0]))
|
||||
}
|
||||
|
||||
actualSearch := resolvconf.GetSearchDomains([]byte(out))
|
||||
if len(actualSearch) != len(hostSearch) {
|
||||
t.Fatalf("expected '%s' search domain(s), but it has: '%s'", len(hostSearch), len(actualSearch))
|
||||
}
|
||||
for i := range actualSearch {
|
||||
if actualSearch[i] != hostSearch[i] {
|
||||
t.Fatalf("expected '%s' domain, but says: '%s'", actualSearch[i], hostSearch[i])
|
||||
}
|
||||
}
|
||||
|
||||
cmd = exec.Command(dockerBinary, "run", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
|
||||
|
||||
out, _, err = runCommandWithOutput(cmd)
|
||||
if err != nil {
|
||||
t.Fatal(err, out)
|
||||
}
|
||||
|
||||
actualNameservers := resolvconf.GetNameservers([]byte(out))
|
||||
if len(actualNameservers) != len(hostNamservers) {
|
||||
t.Fatalf("expected '%s' nameserver(s), but it has: '%s'", len(hostNamservers), len(actualNameservers))
|
||||
}
|
||||
for i := range actualNameservers {
|
||||
if actualNameservers[i] != hostNamservers[i] {
|
||||
t.Fatalf("expected '%s' nameserver, but says: '%s'", actualNameservers[i], hostNamservers[i])
|
||||
}
|
||||
}
|
||||
|
||||
if actualSearch = resolvconf.GetSearchDomains([]byte(out)); string(actualSearch[0]) != "mydomain" {
|
||||
t.Fatalf("expected 'mydomain', but says: '%s'", string(actualSearch[0]))
|
||||
}
|
||||
|
||||
deleteAllContainers()
|
||||
|
||||
logDone("run - dns options based on host resolv.conf")
|
||||
}
|
||||
|
|
11
opts/opts.go
11
opts/opts.go
|
@ -137,7 +137,16 @@ func ValidateIp4Address(val string) (string, error) {
|
|||
return "", fmt.Errorf("%s is not an ip4 address", val)
|
||||
}
|
||||
|
||||
func ValidateDomain(val string) (string, error) {
|
||||
// Validates domain for resolvconf search configuration.
|
||||
// A zero length domain is represented by .
|
||||
func ValidateDnsSearch(val string) (string, error) {
|
||||
if val = strings.Trim(val, " "); val == "." {
|
||||
return val, nil
|
||||
}
|
||||
return validateDomain(val)
|
||||
}
|
||||
|
||||
func validateDomain(val string) (string, error) {
|
||||
alpha := regexp.MustCompile(`[a-zA-Z]`)
|
||||
if alpha.FindString(val) == "" {
|
||||
return "", fmt.Errorf("%s is not a valid domain", val)
|
||||
|
|
|
@ -23,8 +23,9 @@ func TestValidateIP4(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestValidateDomain(t *testing.T) {
|
||||
func TestValidateDnsSearch(t *testing.T) {
|
||||
valid := []string{
|
||||
`.`,
|
||||
`a`,
|
||||
`a.`,
|
||||
`1.foo`,
|
||||
|
@ -49,7 +50,8 @@ func TestValidateDomain(t *testing.T) {
|
|||
|
||||
invalid := []string{
|
||||
``,
|
||||
`.`,
|
||||
` `,
|
||||
` `,
|
||||
`17`,
|
||||
`17.`,
|
||||
`.17`,
|
||||
|
@ -65,14 +67,14 @@ func TestValidateDomain(t *testing.T) {
|
|||
}
|
||||
|
||||
for _, domain := range valid {
|
||||
if ret, err := ValidateDomain(domain); err != nil || ret == "" {
|
||||
t.Fatalf("ValidateDomain(`"+domain+"`) got %s %s", ret, err)
|
||||
if ret, err := ValidateDnsSearch(domain); err != nil || ret == "" {
|
||||
t.Fatalf("ValidateDnsSearch(`"+domain+"`) got %s %s", ret, err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, domain := range invalid {
|
||||
if ret, err := ValidateDomain(domain); err == nil || ret != "" {
|
||||
t.Fatalf("ValidateDomain(`"+domain+"`) got %s %s", ret, err)
|
||||
if ret, err := ValidateDnsSearch(domain); err == nil || ret != "" {
|
||||
t.Fatalf("ValidateDnsSearch(`"+domain+"`) got %s %s", ret, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,10 +78,12 @@ func Build(path string, dns, dnsSearch []string) error {
|
|||
}
|
||||
}
|
||||
if len(dnsSearch) > 0 {
|
||||
if _, err := content.WriteString("search " + strings.Join(dnsSearch, " ") + "\n"); err != nil {
|
||||
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
|
||||
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(path, content.Bytes(), 0644)
|
||||
}
|
||||
|
|
|
@ -131,3 +131,28 @@ func TestBuild(t *testing.T) {
|
|||
t.Fatalf("Expected to find '%s' got '%s'", expected, content)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildWithZeroLengthDomainSearch(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{"."})
|
||||
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\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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func parseRun(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Conf
|
|||
flPublish opts.ListOpts
|
||||
flExpose opts.ListOpts
|
||||
flDns opts.ListOpts
|
||||
flDnsSearch = opts.NewListOpts(opts.ValidateDomain)
|
||||
flDnsSearch = opts.NewListOpts(opts.ValidateDnsSearch)
|
||||
flVolumesFrom opts.ListOpts
|
||||
flLxcOpts opts.ListOpts
|
||||
flEnvFile opts.ListOpts
|
||||
|
|
Loading…
Reference in a new issue