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")
 | 
							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")
 | 
							flEnableCors         = flag.Bool([]string{"#api-enable-cors", "-api-enable-cors"}, false, "Enable CORS headers in the remote API")
 | 
				
			||||||
		flDns                = opts.NewListOpts(opts.ValidateIp4Address)
 | 
							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")
 | 
							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")
 | 
							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")
 | 
							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 (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
 | 
						"io/ioutil"
 | 
				
			||||||
	"os"
 | 
						"os"
 | 
				
			||||||
	"os/exec"
 | 
						"os/exec"
 | 
				
			||||||
	"reflect"
 | 
						"reflect"
 | 
				
			||||||
| 
						 | 
					@ -10,6 +11,8 @@ import (
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"sync"
 | 
						"sync"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/dotcloud/docker/pkg/networkfs/resolvconf"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// "test123" should be printed by docker run
 | 
					// "test123" should be printed by docker run
 | 
				
			||||||
| 
						 | 
					@ -983,3 +986,109 @@ func TestDisallowBindMountingRootToRoot(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	logDone("run - bind mount /:/ as volume should fail")
 | 
						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)
 | 
						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]`)
 | 
						alpha := regexp.MustCompile(`[a-zA-Z]`)
 | 
				
			||||||
	if alpha.FindString(val) == "" {
 | 
						if alpha.FindString(val) == "" {
 | 
				
			||||||
		return "", fmt.Errorf("%s is not a valid domain", 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{
 | 
						valid := []string{
 | 
				
			||||||
 | 
							`.`,
 | 
				
			||||||
		`a`,
 | 
							`a`,
 | 
				
			||||||
		`a.`,
 | 
							`a.`,
 | 
				
			||||||
		`1.foo`,
 | 
							`1.foo`,
 | 
				
			||||||
| 
						 | 
					@ -49,7 +50,8 @@ func TestValidateDomain(t *testing.T) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	invalid := []string{
 | 
						invalid := []string{
 | 
				
			||||||
		``,
 | 
							``,
 | 
				
			||||||
		`.`,
 | 
							` `,
 | 
				
			||||||
 | 
							`  `,
 | 
				
			||||||
		`17`,
 | 
							`17`,
 | 
				
			||||||
		`17.`,
 | 
							`17.`,
 | 
				
			||||||
		`.17`,
 | 
							`.17`,
 | 
				
			||||||
| 
						 | 
					@ -65,14 +67,14 @@ func TestValidateDomain(t *testing.T) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, domain := range valid {
 | 
						for _, domain := range valid {
 | 
				
			||||||
		if ret, err := ValidateDomain(domain); err != nil || ret == "" {
 | 
							if ret, err := ValidateDnsSearch(domain); err != nil || ret == "" {
 | 
				
			||||||
			t.Fatalf("ValidateDomain(`"+domain+"`) got %s %s", ret, err)
 | 
								t.Fatalf("ValidateDnsSearch(`"+domain+"`) got %s %s", ret, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, domain := range invalid {
 | 
						for _, domain := range invalid {
 | 
				
			||||||
		if ret, err := ValidateDomain(domain); err == nil || ret != "" {
 | 
							if ret, err := ValidateDnsSearch(domain); err == nil || ret != "" {
 | 
				
			||||||
			t.Fatalf("ValidateDomain(`"+domain+"`) got %s %s", ret, err)
 | 
								t.Fatalf("ValidateDnsSearch(`"+domain+"`) got %s %s", ret, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,8 +78,10 @@ func Build(path string, dns, dnsSearch []string) error {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if len(dnsSearch) > 0 {
 | 
						if len(dnsSearch) > 0 {
 | 
				
			||||||
		if _, err := content.WriteString("search " + strings.Join(dnsSearch, " ") + "\n"); err != nil {
 | 
							if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
 | 
				
			||||||
			return err
 | 
								if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -131,3 +131,28 @@ func TestBuild(t *testing.T) {
 | 
				
			||||||
		t.Fatalf("Expected to find '%s' got '%s'", expected, content)
 | 
							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
 | 
							flPublish     opts.ListOpts
 | 
				
			||||||
		flExpose      opts.ListOpts
 | 
							flExpose      opts.ListOpts
 | 
				
			||||||
		flDns         opts.ListOpts
 | 
							flDns         opts.ListOpts
 | 
				
			||||||
		flDnsSearch   = opts.NewListOpts(opts.ValidateDomain)
 | 
							flDnsSearch   = opts.NewListOpts(opts.ValidateDnsSearch)
 | 
				
			||||||
		flVolumesFrom opts.ListOpts
 | 
							flVolumesFrom opts.ListOpts
 | 
				
			||||||
		flLxcOpts     opts.ListOpts
 | 
							flLxcOpts     opts.ListOpts
 | 
				
			||||||
		flEnvFile     opts.ListOpts
 | 
							flEnvFile     opts.ListOpts
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue