Merge pull request #334 from squeed/host-local-dns
ipam/host-local: add ResolvConf argument for DNS configuration
This commit is contained in:
commit
530dd71e19
@ -30,6 +30,7 @@ It stores the state locally on the host filesystem, therefore ensuring uniquenes
|
||||
* `rangeEnd` (string, optional): IP inside of "subnet" with which to end allocating addresses. Defaults to ".254" IP inside of the "subnet" block.
|
||||
* `gateway` (string, optional): IP inside of "subnet" to designate as the gateway. Defaults to ".1" IP inside of the "subnet" block.
|
||||
* `routes` (string, optional): list of routes to add to the container namespace. Each route is a dictionary with "dst" and optional "gw" fields. If "gw" is omitted, value of "gateway" will be used.
|
||||
* `resolvConf` (string, optional): Path to a `resolv.conf` on the host to parse and return as the DNS configuration
|
||||
|
||||
## Supported arguments
|
||||
The following [CNI_ARGS](https://github.com/containernetworking/cni/blob/master/SPEC.md#parameters) are supported:
|
||||
|
@ -1,6 +1,7 @@
|
||||
# host-local IP address manager
|
||||
|
||||
host-local IPAM allocates IPv4 and IPv6 addresses out of a specified address range.
|
||||
host-local IPAM allocates IPv4 and IPv6 addresses out of a specified address range. Optionally,
|
||||
it can include a DNS configuration from a `resolv.conf` file on the host.
|
||||
|
||||
## Usage
|
||||
|
||||
@ -65,7 +66,8 @@ f81d4fae-7dec-11d0-a765-00a0c91e6bf6
|
||||
"rangeEnd": "3ffe:ffff:0:01ff::0020",
|
||||
"routes": [
|
||||
{ "dst": "3ffe:ffff:0:01ff::1/64" }
|
||||
]
|
||||
],
|
||||
"resolvConf": "/etc/resolv.conf"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -32,6 +32,7 @@ type IPAMConfig struct {
|
||||
Gateway net.IP `json:"gateway"`
|
||||
Routes []types.Route `json:"routes"`
|
||||
DataDir string `json:"dataDir"`
|
||||
ResolvConf string `json:"resolvConf"`
|
||||
Args *IPAMArgs `json:"-"`
|
||||
}
|
||||
|
||||
|
64
plugins/ipam/host-local/dns.go
Normal file
64
plugins/ipam/host-local/dns.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2016 CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
)
|
||||
|
||||
// parseResolvConf parses an existing resolv.conf in to a DNS struct
|
||||
func parseResolvConf(filename string) (*types.DNS, error) {
|
||||
fp, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dns := types.DNS{}
|
||||
scanner := bufio.NewScanner(fp)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
line = strings.TrimSpace(line)
|
||||
|
||||
// Skip comments, empty lines
|
||||
if len(line) == 0 || line[0] == '#' || line[0] == ';' {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) < 2 {
|
||||
continue
|
||||
}
|
||||
switch fields[0] {
|
||||
case "nameserver":
|
||||
dns.Nameservers = append(dns.Nameservers, fields[1])
|
||||
case "domain":
|
||||
dns.Domain = fields[1]
|
||||
case "search":
|
||||
dns.Search = append(dns.Search, fields[1:]...)
|
||||
case "options":
|
||||
dns.Options = append(dns.Options, fields[1:]...)
|
||||
}
|
||||
}
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &dns, nil
|
||||
}
|
80
plugins/ipam/host-local/dns_test.go
Normal file
80
plugins/ipam/host-local/dns_test.go
Normal file
@ -0,0 +1,80 @@
|
||||
// Copyright 2016 CNI authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/containernetworking/cni/pkg/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("parsing resolv.conf", func() {
|
||||
It("parses a simple resolv.conf file", func() {
|
||||
contents := `
|
||||
nameserver 192.0.2.0
|
||||
nameserver 192.0.2.1
|
||||
`
|
||||
dns, err := parse(contents)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(*dns).Should(Equal(types.DNS{Nameservers: []string{"192.0.2.0", "192.0.2.1"}}))
|
||||
})
|
||||
It("ignores comments", func() {
|
||||
dns, err := parse(`
|
||||
nameserver 192.0.2.0
|
||||
;nameserver 192.0.2.1
|
||||
`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(*dns).Should(Equal(types.DNS{Nameservers: []string{"192.0.2.0"}}))
|
||||
})
|
||||
It("parses all fields", func() {
|
||||
dns, err := parse(`
|
||||
nameserver 192.0.2.0
|
||||
nameserver 192.0.2.2
|
||||
domain example.com
|
||||
;nameserver comment
|
||||
#nameserver comment
|
||||
search example.net example.org
|
||||
search example.gov
|
||||
options one two three
|
||||
options four
|
||||
`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(*dns).Should(Equal(types.DNS{
|
||||
Nameservers: []string{"192.0.2.0", "192.0.2.2"},
|
||||
Domain: "example.com",
|
||||
Search: []string{"example.net", "example.org", "example.gov"},
|
||||
Options: []string{"one", "two", "three", "four"},
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
func parse(contents string) (*types.DNS, error) {
|
||||
f, err := ioutil.TempFile("", "host_local_resolv")
|
||||
defer f.Close()
|
||||
defer os.Remove(f.Name())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err := f.WriteString(contents); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return parseResolvConf(f.Name())
|
||||
}
|
@ -38,6 +38,9 @@ var _ = Describe("host-local Operations", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(tmpDir, "resolv.conf"), []byte("nameserver 192.0.2.3"), 0644)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
conf := fmt.Sprintf(`{
|
||||
"cniVersion": "0.2.0",
|
||||
"name": "mynet",
|
||||
@ -46,9 +49,10 @@ var _ = Describe("host-local Operations", func() {
|
||||
"ipam": {
|
||||
"type": "host-local",
|
||||
"subnet": "10.1.2.0/24",
|
||||
"dataDir": "%s"
|
||||
"dataDir": "%s",
|
||||
"resolvConf": "%s/resolv.conf"
|
||||
}
|
||||
}`, tmpDir)
|
||||
}`, tmpDir, tmpDir)
|
||||
|
||||
args := &skel.CmdArgs{
|
||||
ContainerID: "dummy",
|
||||
@ -80,6 +84,8 @@ var _ = Describe("host-local Operations", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(string(contents)).To(Equal("10.1.2.2"))
|
||||
|
||||
Expect(result.DNS).To(Equal(types.DNS{Nameservers: []string{"192.0.2.3"}}))
|
||||
|
||||
// Release the IP
|
||||
err = testutils.CmdDelWithResult(nspath, ifname, func() error {
|
||||
return cmdDel(args)
|
||||
|
@ -33,6 +33,16 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
return err
|
||||
}
|
||||
|
||||
r := types.Result{}
|
||||
|
||||
if ipamConf.ResolvConf != "" {
|
||||
dns, err := parseResolvConf(ipamConf.ResolvConf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.DNS = *dns
|
||||
}
|
||||
|
||||
store, err := disk.New(ipamConf.Name, ipamConf.DataDir)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -48,10 +58,8 @@ func cmdAdd(args *skel.CmdArgs) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.IP4 = ipConf
|
||||
|
||||
r := &types.Result{
|
||||
IP4: ipConf,
|
||||
}
|
||||
return r.Print()
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user