Browse code

Add support for DNS options

Signed-off-by: Tim Hockin <thockin@google.com>

Tim Hockin authored on 2015/09/01 03:47:25
Showing 22 changed files
... ...
@@ -533,6 +533,7 @@ _docker_daemon() {
533 533
 		--default-ulimit
534 534
 		--dns
535 535
 		--dns-search
536
+		--dns-opt
536 537
 		--exec-driver -e
537 538
 		--exec-opt
538 539
 		--exec-root
... ...
@@ -1124,6 +1125,7 @@ _docker_run() {
1124 1124
 		--cpu-shares -c
1125 1125
 		--device
1126 1126
 		--dns
1127
+		--dns-opt
1127 1128
 		--dns-search
1128 1129
 		--entrypoint
1129 1130
 		--env -e
... ...
@@ -49,6 +49,7 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -l bip -d "Use this CIDR
49 49
 complete -c docker -f -n '__fish_docker_no_subcommand' -s D -l debug -d 'Enable debug mode'
50 50
 complete -c docker -f -n '__fish_docker_no_subcommand' -s d -l daemon -d 'Enable daemon mode'
51 51
 complete -c docker -f -n '__fish_docker_no_subcommand' -l dns -d 'Force Docker to use specific DNS servers'
52
+complete -c docker -f -n '__fish_docker_no_subcommand' -l dns-opt -d 'Force Docker to use specific DNS options'
52 53
 complete -c docker -f -n '__fish_docker_no_subcommand' -l dns-search -d 'Force Docker to use specific DNS search domains'
53 54
 complete -c docker -f -n '__fish_docker_no_subcommand' -s e -l exec-driver -d 'Force the Docker runtime to use a specific exec driver'
54 55
 complete -c docker -f -n '__fish_docker_no_subcommand' -l exec-opt -d 'Set exec driver options'
... ...
@@ -122,6 +123,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cidfile -d '
122 122
 complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l cpuset -d 'CPUs in which to allow execution (0-3, 0,1)'
123 123
 complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)'
124 124
 complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns -d 'Set custom DNS servers'
125
+complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns-opt -d "Set custom DNS options (Use --dns-opt='' if you don't wish to set options)"
125 126
 complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l dns-search -d "Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)"
126 127
 complete -c docker -A -f -n '__fish_seen_subcommand_from create' -s e -l env -d 'Set environment variables'
127 128
 complete -c docker -A -f -n '__fish_seen_subcommand_from create' -l entrypoint -d 'Overwrite the default ENTRYPOINT of the image'
... ...
@@ -309,6 +311,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l cpuset -d 'CPUs
309 309
 complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s d -l detach -d 'Detached mode: run the container in the background and print the new container ID'
310 310
 complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l device -d 'Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)'
311 311
 complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns -d 'Set custom DNS servers'
312
+complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns-opt -d "Set custom DNS options (Use --dns-opt='' if you don't wish to set options)"
312 313
 complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l dns-search -d "Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)"
313 314
 complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s e -l env -d 'Set environment variables'
314 315
 complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l entrypoint -d 'Overwrite the default ENTRYPOINT of the image'
... ...
@@ -226,8 +226,9 @@ __docker_subcommand() {
226 226
         "($help)*--cap-drop=-[Drop Linux capabilities]:capability: "
227 227
         "($help)--cidfile=-[Write the container ID to the file]:CID file:_files"
228 228
         "($help)*--device=-[Add a host device to the container]:device:_files"
229
-        "($help)*--dns=-[Set custom dns servers]:dns server: "
230
-        "($help)*--dns-search=-[Set custom DNS search domains]:dns domains: "
229
+        "($help)*--dns=-[Set custom DNS servers]:DNS server: "
230
+        "($help)*--dns-opt=-[Set custom DNS options]:DNS option: "
231
+        "($help)*--dns-search=-[Set custom DNS search domains]:DNS domains: "
231 232
         "($help)*"{-e,--env=-}"[Set environment variables]:environment variable: "
232 233
         "($help)--entrypoint=-[Overwrite the default entrypoint of the image]:entry point: "
233 234
         "($help)*--env-file=-[Read environment variables from a file]:environment file:_files"
... ...
@@ -599,7 +600,8 @@ _docker() {
599 599
         "($help)--default-gateway[Container default gateway IPv4 address]:IPv4 address: " \
600 600
         "($help)--default-gateway-v6[Container default gateway IPv6 address]:IPv6 address: " \
601 601
         "($help)*--dns=-[DNS server to use]:DNS: " \
602
-        "($help)*--dns-search=-[DNS search domains to use]" \
602
+        "($help)*--dns-search=-[DNS search domains to use]:DNS search: " \
603
+        "($help)*--dns-opt=-[DNS options to use]:DNS option: " \
603 604
         "($help)*--default-ulimit=-[Set default ulimit settings for containers]:ulimit: " \
604 605
         "($help -e --exec-driver)"{-e,--exec-driver=-}"[Exec driver to use]:driver:(native lxc windows)" \
605 606
         "($help)*--exec-opt=-[Set exec driver options]:exec driver options: " \
... ...
@@ -19,6 +19,7 @@ type CommonConfig struct {
19 19
 	Context        map[string][]string
20 20
 	DisableBridge  bool
21 21
 	DNS            []string
22
+	DNSOptions     []string
22 23
 	DNSSearch      []string
23 24
 	ExecDriver     string
24 25
 	ExecOptions    []string
... ...
@@ -51,6 +52,7 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string)
51 51
 	cmd.IntVar(&config.Mtu, []string{"#mtu", "-mtu"}, 0, usageFn("Set the containers network MTU"))
52 52
 	// FIXME: why the inconsistency between "hosts" and "sockets"?
53 53
 	cmd.Var(opts.NewListOptsRef(&config.DNS, opts.ValidateIPAddress), []string{"#dns", "-dns"}, usageFn("DNS server to use"))
54
+	cmd.Var(opts.NewListOptsRef(&config.DNSOptions, nil), []string{"-dns-opt"}, usageFn("DNS options to use"))
54 55
 	cmd.Var(opts.NewListOptsRef(&config.DNSSearch, opts.ValidateDNSSearch), []string{"-dns-search"}, usageFn("DNS search domains to use"))
55 56
 	cmd.Var(opts.NewListOptsRef(&config.Labels, opts.ValidateLabel), []string{"-label"}, usageFn("Set key=value labels to the daemon"))
56 57
 	cmd.StringVar(&config.LogConfig.Type, []string{"-log-driver"}, "json-file", usageFn("Default driver for container logs"))
... ...
@@ -397,6 +397,7 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e
397 397
 		err         error
398 398
 		dns         []string
399 399
 		dnsSearch   []string
400
+		dnsOptions  []string
400 401
 	)
401 402
 
402 403
 	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
... ...
@@ -444,6 +445,16 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e
444 444
 		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
445 445
 	}
446 446
 
447
+	if len(container.hostConfig.DNSOptions) > 0 {
448
+		dnsOptions = container.hostConfig.DNSOptions
449
+	} else if len(container.daemon.configStore.DNSOptions) > 0 {
450
+		dnsOptions = container.daemon.configStore.DNSOptions
451
+	}
452
+
453
+	for _, ds := range dnsOptions {
454
+		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
455
+	}
456
+
447 457
 	if container.NetworkSettings.SecondaryIPAddresses != nil {
448 458
 		name := container.Config.Hostname
449 459
 		if container.Config.Domainname != "" {
... ...
@@ -174,7 +174,7 @@ func TestLoadWithVolume(t *testing.T) {
174 174
 	}
175 175
 
176 176
 	hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
177
-"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
177
+"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
178 178
 "Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
179 179
 "SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
180 180
 	if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
... ...
@@ -262,7 +262,7 @@ func TestLoadWithBindMount(t *testing.T) {
262 262
 	}
263 263
 
264 264
 	hostConfig := `{"Binds":["/vol1:/vol1"],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
265
-"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
265
+"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
266 266
 "Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
267 267
 "SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
268 268
 	if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
... ...
@@ -353,7 +353,7 @@ func TestLoadWithVolume17RC(t *testing.T) {
353 353
 	}
354 354
 
355 355
 	hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
356
-"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
356
+"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
357 357
 "Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
358 358
 "SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
359 359
 	if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
... ...
@@ -458,7 +458,7 @@ func TestRemoveLocalVolumesFollowingSymlinks(t *testing.T) {
458 458
 	}
459 459
 
460 460
 	hostConfig := `{"Binds":[],"ContainerIDFile":"","LxcConf":[],"Memory":0,"MemorySwap":0,"CpuShares":0,"CpusetCpus":"",
461
-"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
461
+"Privileged":false,"PortBindings":{},"Links":null,"PublishAllPorts":false,"Dns":null,"DnsOptions":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,
462 462
 "Devices":[],"NetworkMode":"bridge","IpcMode":"","PidMode":"","CapAdd":null,"CapDrop":null,"RestartPolicy":{"Name":"no","MaximumRetryCount":0},
463 463
 "SecurityOpt":null,"ReadonlyRootfs":false,"Ulimits":null,"LogConfig":{"Type":"","Config":null},"CgroupParent":""}`
464 464
 	if err = ioutil.WriteFile(filepath.Join(containerPath, "hostconfig.json"), []byte(hostConfig), 0644); err != nil {
... ...
@@ -102,7 +102,7 @@ server when it starts up, and cannot be changed once it is running:
102 102
  *  `--userland-proxy=true|false` — see
103 103
     [Binding container ports](#binding-ports)
104 104
 
105
-There are two networking options that can be supplied either at startup
105
+There are three networking options that can be supplied either at startup
106 106
 or when `docker run` is invoked.  When provided at startup, set the
107 107
 default value that `docker run` will later use if the options are not
108 108
 specified:
... ...
@@ -113,6 +113,9 @@ specified:
113 113
  *  `--dns-search=DOMAIN...` — see
114 114
     [Configuring DNS](#dns)
115 115
 
116
+ *  `--dns-opt=OPTION...` — see
117
+    [Configuring DNS](#dns)
118
+
116 119
 Finally, several networking options can only be provided when calling
117 120
 `docker run` because they specify something specific to one container:
118 121
 
... ...
@@ -215,12 +218,16 @@ Four different options affect container domain name services.
215 215
     only look up `host` but also `host.example.com`.
216 216
     Use `--dns-search=.` if you don't wish to set the search domain.
217 217
 
218
-Regarding DNS settings, in the absence of either the `--dns=IP_ADDRESS...`
219
-or the `--dns-search=DOMAIN...` option, Docker makes each container's
220
-`/etc/resolv.conf` look like the `/etc/resolv.conf` of the host machine (where
221
-the `docker` daemon runs).  When creating the container's `/etc/resolv.conf`,
222
-the daemon filters out all localhost IP address `nameserver` entries from
223
-the host's original file.
218
+ *  `--dns-opt=OPTION...` — sets the options used by DNS resolvers
219
+    by writing an `options` line into the container's `/etc/resolv.conf`.
220
+    See documentation for `resolv.conf` for a list of valid options.
221
+
222
+Regarding DNS settings, in the absence of the `--dns=IP_ADDRESS...`,
223
+`--dns-search=DOMAIN...`, or `--dns-opt=OPTION...` options, Docker makes
224
+each container's `/etc/resolv.conf` look like the `/etc/resolv.conf` of the
225
+host machine (where the `docker` daemon runs).  When creating the container's
226
+`/etc/resolv.conf`, the daemon filters out all localhost IP address
227
+`nameserver` entries from the host's original file.
224 228
 
225 229
 Filtering is necessary because all localhost addresses on the host are
226 230
 unreachable from the container's network.  After this filtering, if there 
... ...
@@ -253,9 +260,9 @@ of a facility to ensure atomic writes of the `resolv.conf` file while the
253 253
 container is running. If the container's `resolv.conf` has been edited since
254 254
 it was started with the default configuration, no replacement will be
255 255
 attempted as it would overwrite the changes performed by the container.
256
-If the options (`--dns` or `--dns-search`) have been used to modify the 
257
-default host configuration, then the replacement with an updated host's
258
-`/etc/resolv.conf` will not happen as well.
256
+If the options (`--dns`, `--dns-search`, or `--dns-opt`) have been used to
257
+modify the default host configuration, then the replacement with an updated
258
+host's `/etc/resolv.conf` will not happen as well.
259 259
 
260 260
 > **Note**:
261 261
 > For containers which were created prior to the implementation of
... ...
@@ -84,6 +84,8 @@ This section lists each version from latest to oldest.  Each listing includes a
84 84
 * `GET /images/(name)/json` now returns information about tags of the image.
85 85
 * The `config` option now accepts the field `StopSignal`, which specifies the signal to use to kill a container.
86 86
 * `GET /containers/(id)/stats` will return networking information respectively for each interface.
87
+* The `hostConfig` option now accepts the field `DnsOptions`, which specifies a
88
+list of DNS options to be used in the container.
87 89
 
88 90
 
89 91
 ### v1.20 API changes
... ...
@@ -186,6 +186,7 @@ Create a container
186 186
              "Privileged": false,
187 187
              "ReadonlyRootfs": false,
188 188
              "Dns": ["8.8.8.8"],
189
+             "DnsOptions": [""],
189 190
              "DnsSearch": [""],
190 191
              "ExtraHosts": null,
191 192
              "VolumesFrom": ["parent", "other:ro"],
... ...
@@ -272,6 +273,7 @@ Json Parameters:
272 272
     -   **ReadonlyRootfs** - Mount the container's root filesystem as read only.
273 273
           Specified as a boolean value.
274 274
     -   **Dns** - A list of DNS servers for the container to use.
275
+    -   **DnsOptions** - A list of DNS options
275 276
     -   **DnsSearch** - A list of DNS search domains
276 277
     -   **ExtraHosts** - A list of hostnames/IP mappings to add to the
277 278
         container's `/etc/hosts` file. Specified in the form `["hostname:IP"]`.
... ...
@@ -388,6 +390,7 @@ Return low-level information on the container `id`
388 388
 			"CpuPeriod": 100000,
389 389
 			"Devices": [],
390 390
 			"Dns": null,
391
+			"DnsOptions": null,
391 392
 			"DnsSearch": null,
392 393
 			"ExtraHosts": null,
393 394
 			"IpcMode": "",
... ...
@@ -31,6 +31,7 @@ Creates a new container.
31 31
       --cpuset-mems=""              Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
32 32
       --device=[]                   Add a host device to the container
33 33
       --dns=[]                      Set custom DNS servers
34
+      --dns-opt=[]                  Set custom DNS options
34 35
       --dns-search=[]               Set custom DNS search domains
35 36
       -e, --env=[]                  Set environment variables
36 37
       --entrypoint=""               Overwrite the default ENTRYPOINT of the image
... ...
@@ -23,6 +23,7 @@ weight=1
23 23
       --default-gateway=""                   Container default gateway IPv4 address
24 24
       --default-gateway-v6=""                Container default gateway IPv6 address
25 25
       --dns=[]                               DNS server to use
26
+      --dns-opt=[]                           DNS options to use
26 27
       --dns-search=[]                        DNS search domains to use
27 28
       --default-ulimit=[]                    Set default ulimit settings for containers
28 29
       -e, --exec-driver="native"             Exec driver to use
... ...
@@ -30,6 +30,7 @@ weight=1
30 30
       -d, --detach=false            Run container in background and print container ID
31 31
       --device=[]                   Add a host device to the container
32 32
       --dns=[]                      Set custom DNS servers
33
+      --dns-opt=[]                  Set custom DNS options
33 34
       --dns-search=[]               Set custom DNS search domains
34 35
       -e, --env=[]                  Set environment variables
35 36
       --entrypoint=""               Overwrite the default ENTRYPOINT of the image
... ...
@@ -330,8 +330,8 @@ traffic will be routed though this bridge to the container.
330 330
 With the networking mode set to `host` a container will share the host's
331 331
 network stack and all interfaces from the host will be available to the
332 332
 container.  The container's hostname will match the hostname on the host
333
-system.  Note that `--add-host` `--hostname`  `--dns` `--dns-search` and
334
-`--mac-address` is invalid in `host` netmode.
333
+system.  Note that `--add-host` `--hostname`  `--dns` `--dns-search`
334
+`--dns-opt` and `--mac-address` are invalid in `host` netmode.
335 335
 
336 336
 Compared to the default `bridge` mode, the `host` mode gives *significantly*
337 337
 better networking performance since it uses the host's native networking stack
... ...
@@ -348,9 +348,9 @@ or a High Performance Web Server.
348 348
 With the networking mode set to `container` a container will share the
349 349
 network stack of another container.  The other container's name must be
350 350
 provided in the format of `--net container:<name|id>`. Note that `--add-host`
351
-`--hostname` `--dns` `--dns-search` and `--mac-address` is invalid
352
-in `container` netmode, and `--publish` `--publish-all` `--expose` are also
353
-invalid in `container` netmode.
351
+`--hostname` `--dns` `--dns-search` `--dns-opt` and `--mac-address` are
352
+invalid in `container` netmode, and `--publish` `--publish-all` `--expose` are
353
+also invalid in `container` netmode.
354 354
 
355 355
 Example running a Redis container with Redis binding to `localhost` then
356 356
 running the `redis-cli` command and connecting to the Redis server over the
... ...
@@ -940,7 +940,7 @@ func (s *DockerSuite) TestRunDnsDefaultOptions(c *check.C) {
940 940
 
941 941
 func (s *DockerSuite) TestRunDnsOptions(c *check.C) {
942 942
 	testRequires(c, DaemonIsLinux)
943
-	out, stderr, _ := dockerCmdWithStdoutStderr(c, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "busybox", "cat", "/etc/resolv.conf")
943
+	out, stderr, _ := dockerCmdWithStdoutStderr(c, "run", "--dns=127.0.0.1", "--dns-search=mydomain", "--dns-opt=ndots:9", "busybox", "cat", "/etc/resolv.conf")
944 944
 
945 945
 	// The client will get a warning on stderr when setting DNS to a localhost address; verify this:
946 946
 	if !strings.Contains(stderr, "Localhost DNS setting") {
... ...
@@ -948,15 +948,25 @@ func (s *DockerSuite) TestRunDnsOptions(c *check.C) {
948 948
 	}
949 949
 
950 950
 	actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
951
-	if actual != "search mydomain nameserver 127.0.0.1" {
952
-		c.Fatalf("expected 'nameserver 127.0.0.1 search mydomain', but says: %q", actual)
951
+	if actual != "search mydomain nameserver 127.0.0.1 options ndots:9" {
952
+		c.Fatalf("expected 'search mydomain nameserver 127.0.0.1 options ndots:9', but says: %q", actual)
953 953
 	}
954 954
 
955
-	out, stderr, _ = dockerCmdWithStdoutStderr(c, "run", "--dns=127.0.0.1", "--dns-search=.", "busybox", "cat", "/etc/resolv.conf")
955
+	out, stderr, _ = dockerCmdWithStdoutStderr(c, "run", "--dns=127.0.0.1", "--dns-search=.", "--dns-opt=ndots:3", "busybox", "cat", "/etc/resolv.conf")
956 956
 
957 957
 	actual = strings.Replace(strings.Trim(strings.Trim(out, "\r\n"), " "), "\n", " ", -1)
958
-	if actual != "nameserver 127.0.0.1" {
959
-		c.Fatalf("expected 'nameserver 127.0.0.1', but says: %q", actual)
958
+	if actual != "nameserver 127.0.0.1 options ndots:3" {
959
+		c.Fatalf("expected 'nameserver 127.0.0.1 options ndots:3', but says: %q", actual)
960
+	}
961
+}
962
+
963
+func (s *DockerSuite) TestRunDnsRepeatOptions(c *check.C) {
964
+	testRequires(c, DaemonIsLinux)
965
+	out, _, _ := dockerCmdWithStdoutStderr(c, "run", "--dns=1.1.1.1", "--dns=2.2.2.2", "--dns-search=mydomain", "--dns-search=mydomain2", "--dns-opt=ndots:9", "--dns-opt=timeout:3", "busybox", "cat", "/etc/resolv.conf")
966
+
967
+	actual := strings.Replace(strings.Trim(out, "\r\n"), "\n", " ", -1)
968
+	if actual != "search mydomain mydomain2 nameserver 1.1.1.1 nameserver 2.2.2.2 options ndots:9 timeout:3" {
969
+		c.Fatalf("expected 'search mydomain mydomain2 nameserver 1.1.1.1 nameserver 2.2.2.2 options ndots:9 timeout:3', but says: %q", actual)
960 970
 	}
961 971
 }
962 972
 
... ...
@@ -21,6 +21,7 @@ docker-create - Create a new container
21 21
 [**--device**[=*[]*]]
22 22
 [**--dns**[=*[]*]]
23 23
 [**--dns-search**[=*[]*]]
24
+[**--dns-opt**[=*[]*]]
24 25
 [**-e**|**--env**[=*[]*]]
25 26
 [**--entrypoint**[=*ENTRYPOINT*]]
26 27
 [**--env-file**[=*[]*]]
... ...
@@ -118,6 +119,9 @@ two memory nodes.
118 118
 **--dns**=[]
119 119
    Set custom DNS servers
120 120
 
121
+**--dns-opt**=[]
122
+   Set custom DNS options
123
+
121 124
 **--dns-search**=[]
122 125
    Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)
123 126
 
... ...
@@ -123,6 +123,7 @@ To get information on a container use its ID or instance name:
123 123
         "PublishAllPorts": false,
124 124
         "Dns": null,
125 125
         "DnsSearch": null,
126
+        "DnsOptions": null,
126 127
         "ExtraHosts": null,
127 128
         "VolumesFrom": null,
128 129
         "Devices": [],
... ...
@@ -21,6 +21,7 @@ docker-run - Run a command in a new container
21 21
 [**-d**|**--detach**[=*false*]]
22 22
 [**--device**[=*[]*]]
23 23
 [**--dns**[=*[]*]]
24
+[**--dns-opt**[=*[]*]]
24 25
 [**--dns-search**[=*[]*]]
25 26
 [**-e**|**--env**[=*[]*]]
26 27
 [**--entrypoint**[=*ENTRYPOINT*]]
... ...
@@ -185,6 +186,9 @@ stopping the process by pressing the keys CTRL-P CTRL-Q.
185 185
 **--dns-search**=[]
186 186
    Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)
187 187
 
188
+**--dns-opt**=[]
189
+   Set custom DNS options
190
+
188 191
 **--dns**=[]
189 192
    Set custom DNS servers
190 193
 
... ...
@@ -56,6 +56,9 @@ To see the man page for a command run **man docker <command>**.
56 56
 **--dns**=""
57 57
   Force Docker to use specific DNS servers
58 58
 
59
+**--dns-opt**=[]
60
+  DNS options to use.
61
+
59 62
 **--dns-search**=[]
60 63
   DNS search domains to use.
61 64
 
... ...
@@ -38,6 +38,7 @@
38 38
        "ReadonlyRootfs": false,
39 39
        "Dns": ["8.8.8.8"],
40 40
        "DnsSearch": [""],
41
+       "DnsOptions": [""],
41 42
        "ExtraHosts": null,
42 43
        "VolumesFrom": ["parent", "other:ro"],
43 44
        "CapAdd": ["NET_ADMIN"],
... ...
@@ -42,6 +42,7 @@
42 42
        "ReadonlyRootfs": false,
43 43
        "Dns": ["8.8.8.8"],
44 44
        "DnsSearch": [""],
45
+       "DnsOptions": [""],
45 46
        "ExtraHosts": null,
46 47
        "VolumesFrom": ["parent", "other:ro"],
47 48
        "CapAdd": ["NET_ADMIN"],
... ...
@@ -232,8 +232,9 @@ type HostConfig struct {
232 232
 	PortBindings     nat.PortMap           // Port mapping between the exposed port (container) and the host
233 233
 	Links            []string              // List of links (in the name:alias form)
234 234
 	PublishAllPorts  bool                  // Should docker publish all exposed port for the container
235
-	DNS              []string              `json:"Dns"`       // List of DNS server to lookup
236
-	DNSSearch        []string              `json:"DnsSearch"` // List of DNSSearch to look for
235
+	DNS              []string              `json:"Dns"`        // List of DNS server to lookup
236
+	DNSOptions       []string              `json:"DnsOptions"` // List of DNSOption to look for
237
+	DNSSearch        []string              `json:"DnsSearch"`  // List of DNSSearch to look for
237 238
 	ExtraHosts       []string              // List of extra hosts
238 239
 	VolumesFrom      []string              // List of volumes to take from other container
239 240
 	Devices          []DeviceMapping       // List of devices to map inside the container
... ...
@@ -52,6 +52,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
52 52
 		flExpose      = opts.NewListOpts(nil)
53 53
 		flDNS         = opts.NewListOpts(opts.ValidateIPAddress)
54 54
 		flDNSSearch   = opts.NewListOpts(opts.ValidateDNSSearch)
55
+		flDNSOptions  = opts.NewListOpts(nil)
55 56
 		flExtraHosts  = opts.NewListOpts(opts.ValidateExtraHost)
56 57
 		flVolumesFrom = opts.NewListOpts(nil)
57 58
 		flLxcOpts     = opts.NewListOpts(nil)
... ...
@@ -109,6 +110,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
109 109
 	cmd.Var(&flExpose, []string{"#expose", "-expose"}, "Expose a port or a range of ports")
110 110
 	cmd.Var(&flDNS, []string{"#dns", "-dns"}, "Set custom DNS servers")
111 111
 	cmd.Var(&flDNSSearch, []string{"-dns-search"}, "Set custom DNS search domains")
112
+	cmd.Var(&flDNSOptions, []string{"-dns-opt"}, "Set DNS options")
112 113
 	cmd.Var(&flExtraHosts, []string{"-add-host"}, "Add a custom host-to-IP mapping (host:ip)")
113 114
 	cmd.Var(&flVolumesFrom, []string{"#volumes-from", "-volumes-from"}, "Mount volumes from the specified container(s)")
114 115
 	cmd.Var(&flLxcOpts, []string{"#lxc-conf", "-lxc-conf"}, "Add custom lxc options")
... ...
@@ -347,6 +349,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
347 347
 		PublishAllPorts:  *flPublishAll,
348 348
 		DNS:              flDNS.GetAll(),
349 349
 		DNSSearch:        flDNSSearch.GetAll(),
350
+		DNSOptions:       flDNSOptions.GetAll(),
350 351
 		ExtraHosts:       flExtraHosts.GetAll(),
351 352
 		VolumesFrom:      flVolumesFrom.GetAll(),
352 353
 		NetworkMode:      NetworkMode(*flNetMode),