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…
Reference in a new issue