daemon/libnetwork/resolvconf: remove unused code

This package is a wrapper for the libnetwork/internal/resolvconf package,
which is a modernized, more performant rewrite of the original parsing
code.

The libnetwork/resolvconf package was still maintained because it was
used by BuildKit, but since [moby/buildkit@3d43066], BuildKit maintains
its own copy of the internal package.

The only remaining uses of this package was as part of some tests (which
would also benefit of using the internal pacakge's implementation directly),
and a _single_ use of `resolvconf.Path` in the daemon, which cannot use
the internal package currently because it's internal to libnetwork.

This patch:

- Removes all functions that were not used.
- Rewrites some tests in libnetwork to use the internal/resolvconf package
  directly, instead of depending on the wrapper.
- Add TODOs to consider moving the "Path" function separate (which could
  be in daemon/config if we consider it to be the default for the daemon's
  resolvconf path configuration).

[moby/buildkit@3d43066]: https://github.com/moby/buildkit/commit/3d43066f2e814d4d10383ba871256245edf08a25

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Sebastiaan van Stijn committed 2025-08-01 14:48:05 +02:00
1 parent 8c5c253b50
commit 0156a42200
7 files changed
+103 -631

No files matched your search

+1
View File
@@ -146,6 +146,7 @@ func setupResolvConf(config *config.Config) {
if config.ResolvConf != "" {
return
}
// FIXME(thaJeztah): we can't use [github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf.Path] here, because it's internal to libnetwork.
config.ResolvConf = resolvconf.Path()
}
+19 -2
View File
@@ -3,14 +3,15 @@
package netutils
import (
"bytes"
"net/netip"
"os"
"slices"
"github.com/moby/moby/v2/daemon/libnetwork/internal/netiputil"
"github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf"
"github.com/moby/moby/v2/daemon/libnetwork/nlwrap"
"github.com/moby/moby/v2/daemon/libnetwork/ns"
"github.com/moby/moby/v2/daemon/libnetwork/resolvconf"
"github.com/moby/moby/v2/daemon/libnetwork/types"
"github.com/pkg/errors"
"github.com/vishvananda/netlink"
@@ -62,7 +63,7 @@ func InferReservedNetworks(v6 bool) []netip.Prefix {
// We don't really care if os.ReadFile fails here. It either doesn't exist,
// or we can't read it for some reason.
if rc, err := os.ReadFile(resolvconf.Path()); err == nil {
reserved = slices.DeleteFunc(resolvconf.GetNameserversAsPrefix(rc), func(p netip.Prefix) bool {
reserved = slices.DeleteFunc(tryGetNameserversAsPrefix(rc), func(p netip.Prefix) bool {
return p.Addr().Is6() != v6
})
}
@@ -75,6 +76,22 @@ func InferReservedNetworks(v6 bool) []netip.Prefix {
return reserved
}
// tryGetNameserversAsPrefix returns nameservers (if any) listed in
// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32"). It ignores
// failures to parse the file, as this utility is used as a "best-effort".
func tryGetNameserversAsPrefix(resolvConf []byte) []netip.Prefix {
rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "")
if err != nil {
return nil
}
nsAddrs := rc.NameServers()
nameservers := make([]netip.Prefix, 0, len(nsAddrs))
for _, addr := range nsAddrs {
nameservers = append(nameservers, netip.PrefixFrom(addr, addr.BitLen()))
}
return nameservers
}
// queryOnLinkRoutes returns a list of on-link routes available on the host.
// Only IPv4 prefixes are returned as there's no such thing as on-link
// routes for IPv6.
@@ -8,6 +8,7 @@ import (
"strings"
"testing"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/moby/moby/v2/daemon/libnetwork/internal/netiputil"
"github.com/moby/moby/v2/internal/testutils/netnsutils"
"github.com/vishvananda/netlink"
@@ -60,6 +61,61 @@ func TestGenerateRandomName(t *testing.T) {
}
}
func TestGetNameserversAsPrefix(t *testing.T) {
for _, tc := range []struct {
input string
result []netip.Prefix
}{
{
input: ``,
result: []netip.Prefix{},
},
{
input: `search example.com`,
result: []netip.Prefix{},
},
{
input: ` nameserver 1.2.3.4 `,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
},
{
input: `
nameserver 1.2.3.4
nameserver 40.3.200.10
search example.com`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("40.3.200.10/32")},
},
{
input: `nameserver 1.2.3.4
search example.com
nameserver 4.30.20.100`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("4.30.20.100/32")},
},
{
input: `search example.com
nameserver 1.2.3.4
#nameserver 4.3.2.1`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
},
{
input: `search example.com
nameserver 1.2.3.4 # not 4.3.2.1`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
},
{
input: `nameserver fd6f:c490:ec68::1`,
result: []netip.Prefix{netip.MustParsePrefix("fd6f:c490:ec68::1/128")},
},
{
input: `nameserver fe80::1234%eth0`,
result: []netip.Prefix{netip.MustParsePrefix("fe80::1234/128")},
},
} {
test := tryGetNameserversAsPrefix([]byte(tc.input))
assert.DeepEqual(t, test, tc.result, cmpopts.EquateComparable(netip.Prefix{}))
}
}
// Test mac generation.
func TestUtilGenerateRandomMAC(t *testing.T) {
mac1 := GenerateRandomMAC()
+8 -153
View File
@@ -1,159 +1,14 @@
// Package resolvconf provides utility code to query and update DNS configuration in /etc/resolv.conf
// Package resolvconf provides utility code to get the host's "resolv.conf" path.
package resolvconf
import (
"bytes"
"fmt"
"net/netip"
"os"
"github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf"
"github.com/opencontainers/go-digest"
)
// constants for the IP address type
const (
IP = iota // IPv4 and IPv6
IPv4
IPv6
)
// File contains the resolv.conf content and its hash
type File struct {
Content []byte
Hash []byte
}
import "github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf"
// Path is an alias for [resolvconf.Path], which is internal to libnetwork.
//
// FIXME(thaJeztah): remove this when possible. This is only used in [github.com/moby/moby/v2/daemon.setupResolvConf].
// Either we can move "libnetwork/internal/resolvconf" to "daemon/internal",
// or move the "Path" function to daemon/config (considering it a default
// for the daemon's config).
func Path() string {
return resolvconf.Path()
}
// Get returns the contents of /etc/resolv.conf and its hash
func Get() (*File, error) {
return GetSpecific(Path())
}
// GetSpecific returns the contents of the user specified resolv.conf file and its hash
func GetSpecific(path string) (*File, error) {
resolv, err := os.ReadFile(path)
if err != nil {
return nil, err
}
hash := digest.FromBytes(resolv)
return &File{Content: resolv, Hash: []byte(hash)}, nil
}
// FilterResolvDNS cleans up the config in resolvConf. It has two main jobs:
// 1. It looks for localhost (127.*|::1) entries in the provided
// resolv.conf, removing local nameserver entries, and, if the resulting
// cleaned config has no defined nameservers left, adds default DNS entries
// 2. Given the caller provides the enable/disable state of IPv6, the filter
// code will remove all IPv6 nameservers if it is not enabled for containers
func FilterResolvDNS(resolvConf []byte, ipv6Enabled bool) (*File, error) {
rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "")
if err != nil {
return nil, err
}
rc.TransformForLegacyNw(ipv6Enabled)
content, err := rc.Generate(false)
if err != nil {
return nil, err
}
hash := digest.FromBytes(content)
return &File{Content: content, Hash: []byte(hash)}, nil
}
// GetNameservers returns nameservers (if any) listed in /etc/resolv.conf
func GetNameservers(resolvConf []byte, kind int) []string {
rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "")
if err != nil {
return nil
}
nsAddrs := rc.NameServers()
var nameservers []string
for _, addr := range nsAddrs {
if kind == IP {
nameservers = append(nameservers, addr.String())
} else if kind == IPv4 && addr.Is4() {
nameservers = append(nameservers, addr.String())
} else if kind == IPv6 && addr.Is6() {
nameservers = append(nameservers, addr.String())
}
}
return nameservers
}
// GetNameserversAsPrefix returns nameservers (if any) listed in
// /etc/resolv.conf as CIDR blocks (e.g., "1.2.3.4/32")
func GetNameserversAsPrefix(resolvConf []byte) []netip.Prefix {
rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "")
if err != nil {
return nil
}
nsAddrs := rc.NameServers()
nameservers := make([]netip.Prefix, 0, len(nsAddrs))
for _, addr := range nsAddrs {
nameservers = append(nameservers, netip.PrefixFrom(addr, addr.BitLen()))
}
return nameservers
}
// GetSearchDomains returns search domains (if any) listed in /etc/resolv.conf
// If more than one search line is encountered, only the contents of the last
// one is returned.
func GetSearchDomains(resolvConf []byte) []string {
rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "")
if err != nil {
return nil
}
return rc.Search()
}
// GetOptions returns options (if any) listed in /etc/resolv.conf
// If more than one options line is encountered, only the contents of the last
// one is returned.
func GetOptions(resolvConf []byte) []string {
rc, err := resolvconf.Parse(bytes.NewBuffer(resolvConf), "")
if err != nil {
return nil
}
return rc.Options()
}
// Build generates and writes a configuration file to path containing a nameserver
// entry for every element in nameservers, a "search" entry for every element in
// dnsSearch, and an "options" entry for every element in dnsOptions. It returns
// a File containing the generated content and its (sha256) hash.
//
// Note that the resolv.conf file is written, but the hash file is not.
func Build(path string, nameservers, dnsSearch, dnsOptions []string) (*File, error) {
var ns []netip.Addr
for _, addr := range nameservers {
ipAddr, err := netip.ParseAddr(addr)
if err != nil {
return nil, fmt.Errorf("bad nameserver address: %w", err)
}
ns = append(ns, ipAddr)
}
rc := resolvconf.ResolvConf{}
rc.OverrideNameServers(ns)
rc.OverrideSearch(dnsSearch)
rc.OverrideOptions(dnsOptions)
content, err := rc.Generate(false)
if err != nil {
return nil, err
}
// Write the resolv.conf file - it's bind-mounted into the container, so can't
// move a temp file into place, just have to truncate and write it.
//
// TODO(thaJeztah): the Build function is currently only used by BuildKit, which only uses "File.Content", and doesn't require the file to be written.
if err := os.WriteFile(path, content, 0o644); err != nil {
return nil, err
}
// TODO(thaJeztah): the Build function is currently only used by BuildKit, which does not use the Hash
hash := digest.FromBytes(content)
return &File{Content: content, Hash: []byte(hash)}, nil
}
@@ -1,455 +0,0 @@
//go:build !windows
package resolvconf
import (
"bytes"
"net/netip"
"os"
"strings"
"testing"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/opencontainers/go-digest"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func TestGet(t *testing.T) {
actual, err := Get()
if err != nil {
t.Fatal(err)
}
expected, err := os.ReadFile(Path())
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(actual.Content, expected) {
t.Errorf("%s and GetResolvConf have different content.", Path())
}
hash := digest.FromBytes(expected)
if !bytes.Equal(actual.Hash, []byte(hash)) {
t.Errorf("%s and GetResolvConf have different hashes.", Path())
}
}
func TestGetNameservers(t *testing.T) {
for _, tc := range []struct {
input string
result []string
}{
{
input: ``,
},
{
input: `search example.com`,
},
{
input: ` nameserver 1.2.3.4 `,
result: []string{"1.2.3.4"},
},
{
input: `
nameserver 1.2.3.4
nameserver 40.3.200.10
search example.com`,
result: []string{"1.2.3.4", "40.3.200.10"},
},
{
input: `nameserver 1.2.3.4
search example.com
nameserver 4.30.20.100`,
result: []string{"1.2.3.4", "4.30.20.100"},
},
{
input: `search example.com
nameserver 1.2.3.4
#nameserver 4.3.2.1`,
result: []string{"1.2.3.4"},
},
{
input: `search example.com
nameserver 1.2.3.4 # not 4.3.2.1`,
result: []string{"1.2.3.4"},
},
} {
test := GetNameservers([]byte(tc.input), IP)
if !strSlicesEqual(test, tc.result) {
t.Errorf("Wrong nameserver string {%s} should be %v. Input: %s", test, tc.result, tc.input)
}
}
}
func TestGetNameserversAsPrefix(t *testing.T) {
for _, tc := range []struct {
input string
result []netip.Prefix
}{
{
input: ``,
result: []netip.Prefix{},
},
{
input: `search example.com`,
result: []netip.Prefix{},
},
{
input: ` nameserver 1.2.3.4 `,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
},
{
input: `
nameserver 1.2.3.4
nameserver 40.3.200.10
search example.com`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("40.3.200.10/32")},
},
{
input: `nameserver 1.2.3.4
search example.com
nameserver 4.30.20.100`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32"), netip.MustParsePrefix("4.30.20.100/32")},
},
{
input: `search example.com
nameserver 1.2.3.4
#nameserver 4.3.2.1`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
},
{
input: `search example.com
nameserver 1.2.3.4 # not 4.3.2.1`,
result: []netip.Prefix{netip.MustParsePrefix("1.2.3.4/32")},
},
{
input: `nameserver fd6f:c490:ec68::1`,
result: []netip.Prefix{netip.MustParsePrefix("fd6f:c490:ec68::1/128")},
},
{
input: `nameserver fe80::1234%eth0`,
result: []netip.Prefix{netip.MustParsePrefix("fe80::1234/128")},
},
} {
test := GetNameserversAsPrefix([]byte(tc.input))
assert.DeepEqual(t, test, tc.result, cmpopts.EquateComparable(netip.Prefix{}))
}
}
func TestGetSearchDomains(t *testing.T) {
for _, tc := range []struct {
input string
result []string
}{
{
input: ``,
},
{
input: `# ignored`,
},
{
input: `search example.com`,
result: []string{"example.com"},
},
{
input: `search example.com # notignored`,
result: []string{"example.com", "#", "notignored"},
},
{
input: ` search example.com `,
result: []string{"example.com"},
},
{
input: ` search example.com # notignored`,
result: []string{"example.com", "#", "notignored"},
},
{
input: `search foo.example.com example.com`,
result: []string{"foo.example.com", "example.com"},
},
{
input: ` search foo.example.com example.com `,
result: []string{"foo.example.com", "example.com"},
},
{
input: ` search foo.example.com example.com # notignored`,
result: []string{"foo.example.com", "example.com", "#", "notignored"},
},
{
input: `nameserver 1.2.3.4
search foo.example.com example.com`,
result: []string{"foo.example.com", "example.com"},
},
{
input: `nameserver 1.2.3.4
search dup1.example.com dup2.example.com
search foo.example.com example.com`,
result: []string{"foo.example.com", "example.com"},
},
{
input: `nameserver 1.2.3.4
search foo.example.com example.com
nameserver 4.30.20.100`,
result: []string{"foo.example.com", "example.com"},
},
{
input: `domain an.example`,
result: []string{"an.example"},
},
} {
test := GetSearchDomains([]byte(tc.input))
if !strSlicesEqual(test, tc.result) {
t.Errorf("Wrong search domain string {%s} should be %v. Input: %s", test, tc.result, tc.input)
}
}
}
func TestGetOptions(t *testing.T) {
for _, tc := range []struct {
input string
result []string
}{
{
input: ``,
},
{
input: `# ignored`,
},
{
input: `; ignored`,
},
{
input: `nameserver 1.2.3.4`,
},
{
input: `options opt1`,
result: []string{"opt1"},
},
{
input: `options opt1 # notignored`,
result: []string{"opt1", "#", "notignored"},
},
{
input: `options opt1 ; notignored`,
result: []string{"opt1", ";", "notignored"},
},
{
input: ` options opt1 `,
result: []string{"opt1"},
},
{
input: ` options opt1 # notignored`,
result: []string{"opt1", "#", "notignored"},
},
{
input: `options opt1 opt2 opt3`,
result: []string{"opt1", "opt2", "opt3"},
},
{
input: `options opt1 opt2 opt3 # notignored`,
result: []string{"opt1", "opt2", "opt3", "#", "notignored"},
},
{
input: ` options opt1 opt2 opt3 `,
result: []string{"opt1", "opt2", "opt3"},
},
{
input: ` options opt1 opt2 opt3 # notignored`,
result: []string{"opt1", "opt2", "opt3", "#", "notignored"},
},
{
input: `nameserver 1.2.3.4
options opt1 opt2 opt3`,
result: []string{"opt1", "opt2", "opt3"},
},
{
input: `nameserver 1.2.3.4
options opt1 opt2
options opt3 opt4`,
result: []string{"opt1", "opt2", "opt3", "opt4"},
},
} {
test := GetOptions([]byte(tc.input))
if !strSlicesEqual(test, tc.result) {
t.Errorf("Wrong options string {%s} should be %v. Input: %s", test, tc.result, tc.input)
}
}
}
func strSlicesEqual(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}
const (
// Example IP-addresses as defined in [RFC 5737], [RFC 3849, section 2].
//
// [RFC 5737]: https://datatracker.ietf.org/doc/html/rfc5737
// [RFC 3849, section 2]: https://datatracker.ietf.org/doc/html/rfc3849#section-2
testNS1 = "192.0.2.1"
testNS2 = "2001:db8::1"
testNS3 = "203.0.113.3"
)
func TestBuild(t *testing.T) {
tests := []struct {
doc string
nameServers []string
dnsSearch []string
dnsOptions []string
expOut string
expErr string
}{
{
doc: "no options",
expOut: ``,
},
{
doc: "all options",
nameServers: []string{testNS1, testNS2, testNS3},
dnsSearch: []string{"search1"},
dnsOptions: []string{"opt1"},
expOut: `nameserver 192.0.2.1
nameserver 2001:db8::1
nameserver 203.0.113.3
search search1
options opt1
`,
},
{
doc: "zero-length dns search",
nameServers: []string{testNS1, testNS2, testNS3},
dnsSearch: []string{"."},
dnsOptions: []string{"opt1"},
expOut: `nameserver 192.0.2.1
nameserver 2001:db8::1
nameserver 203.0.113.3
options opt1
`,
},
{
doc: "no dns options",
nameServers: []string{testNS1, testNS2, testNS3},
dnsSearch: []string{"search1"},
dnsOptions: []string{},
expOut: `nameserver 192.0.2.1
nameserver 2001:db8::1
nameserver 203.0.113.3
search search1
`,
},
{
doc: "invalid nameserver",
nameServers: []string{"resolver.example.com"},
expErr: `bad nameserver address: ParseAddr("resolver.example.com"): unexpected character (at "resolver.example.com")`,
},
}
tmpDir := t.TempDir()
for _, tc := range tests {
t.Run(tc.doc, func(t *testing.T) {
file, err := os.CreateTemp(tmpDir, "")
assert.NilError(t, err)
f, err := Build(file.Name(), tc.nameServers, tc.dnsSearch, tc.dnsOptions)
if tc.expErr != "" {
assert.Error(t, err, tc.expErr)
} else if err != nil {
assert.NilError(t, err)
assert.Equal(t, string(f.Content), tc.expOut)
}
// Verify the content matches the expected; for error-cases,
// this verifies the file is empty.
content, err := os.ReadFile(file.Name())
assert.NilError(t, err)
assert.Equal(t, string(content), tc.expOut)
})
}
}
func TestFilterResolvDNS(t *testing.T) {
testcases := []struct {
name string
input string
ipv6Enabled bool
expOut string
}{
{
name: "No localhost",
input: "nameserver 10.16.60.14\nnameserver 10.16.60.21\n",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "Localhost last",
input: "nameserver 10.16.60.14\nnameserver 10.16.60.21\nnameserver 127.0.0.1\n",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "Localhost middle",
input: "nameserver 10.16.60.14\nnameserver 127.0.0.1\nnameserver 10.16.60.21\n",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "Localhost first",
input: "nameserver 127.0.1.1\nnameserver 10.16.60.14\nnameserver 10.16.60.21\n",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "IPv6 Localhost",
input: "nameserver ::1\nnameserver 10.16.60.14\nnameserver 127.0.2.1\nnameserver 10.16.60.21\n",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "Two IPv6 Localhosts",
input: "nameserver 10.16.60.14\nnameserver ::1\nnameserver 10.16.60.21\nnameserver ::1",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "IPv6 disabled",
input: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "IPv6 link-local disabled",
input: "nameserver 10.16.60.14\nnameserver FE80::BB1%1\nnameserver FE80::BB1%eth0\nnameserver 10.16.60.21",
expOut: "nameserver 10.16.60.14\nnameserver 10.16.60.21",
},
{
name: "IPv6 enabled",
input: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21\nnameserver ::1\n",
ipv6Enabled: true,
expOut: "nameserver 10.16.60.14\nnameserver 2002:dead:beef::1\nnameserver 10.16.60.21",
},
{
// with IPv6 enabled, and no non-localhost servers, Google defaults (both IPv4+IPv6) should be added
name: "localhost only IPv6",
input: "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1",
ipv6Enabled: true,
expOut: "nameserver 8.8.8.8\nnameserver 8.8.4.4\nnameserver 2001:4860:4860::8888\nnameserver 2001:4860:4860::8844",
},
{
// with IPv6 disabled, and no non-localhost servers, Google defaults (only IPv4) should be added
name: "localhost only no IPv6",
input: "nameserver 127.0.0.1\nnameserver ::1\nnameserver 127.0.2.1",
expOut: "nameserver 8.8.8.8\nnameserver 8.8.4.4",
},
}
for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
f, err := FilterResolvDNS([]byte(tc.input), tc.ipv6Enabled)
assert.Check(t, is.Nil(err))
out := strings.TrimSpace(string(f.Content))
assert.Check(t, is.Equal(out, tc.expOut))
})
}
}
+18 -19
View File
@@ -3,15 +3,26 @@
package libnetwork
import (
"bytes"
"context"
"os"
"testing"
"github.com/moby/moby/v2/daemon/libnetwork/config"
"github.com/moby/moby/v2/daemon/libnetwork/resolvconf"
"github.com/moby/moby/v2/daemon/libnetwork/internal/resolvconf"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
)
func getResolvConfOptions(t *testing.T, rcPath string) []string {
t.Helper()
resolv, err := os.ReadFile(rcPath)
assert.NilError(t, err)
rc, err := resolvconf.Parse(bytes.NewBuffer(resolv), "")
assert.NilError(t, err)
return rc.Options()
}
func TestDNSOptions(t *testing.T) {
c, err := New(context.Background(), config.OptionDataDir(t.TempDir()))
assert.NilError(t, err)
@@ -32,26 +43,20 @@ func TestDNSOptions(t *testing.T) {
assert.NilError(t, err)
err = sb.rebuildDNS()
assert.NilError(t, err)
currRC, err := resolvconf.GetSpecific(sb.config.resolvConfPath)
assert.NilError(t, err)
dnsOptionsList := resolvconf.GetOptions(currRC.Content)
dnsOptionsList := getResolvConfOptions(t, sb.config.resolvConfPath)
assert.Check(t, is.Len(dnsOptionsList, 1))
assert.Check(t, is.Equal("ndots:0", dnsOptionsList[0]))
sb.config.dnsOptionsList = []string{"ndots:5"}
err = sb.setupDNS()
assert.NilError(t, err)
currRC, err = resolvconf.GetSpecific(sb.config.resolvConfPath)
assert.NilError(t, err)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsOptionsList = getResolvConfOptions(t, sb.config.resolvConfPath)
assert.Check(t, is.Len(dnsOptionsList, 1))
assert.Check(t, is.Equal("ndots:5", dnsOptionsList[0]))
err = sb.rebuildDNS()
assert.NilError(t, err)
currRC, err = resolvconf.GetSpecific(sb.config.resolvConfPath)
assert.NilError(t, err)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsOptionsList = getResolvConfOptions(t, sb.config.resolvConfPath)
assert.Check(t, is.Len(dnsOptionsList, 1))
assert.Check(t, is.Equal("ndots:5", dnsOptionsList[0]))
@@ -65,9 +70,7 @@ func TestDNSOptions(t *testing.T) {
assert.NilError(t, err)
err = sb2.rebuildDNS()
assert.NilError(t, err)
currRC, err = resolvconf.GetSpecific(sb2.config.resolvConfPath)
assert.NilError(t, err)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath)
assert.Check(t, is.Len(dnsOptionsList, 1))
assert.Check(t, is.Equal("ndots:0", dnsOptionsList[0]))
@@ -76,9 +79,7 @@ func TestDNSOptions(t *testing.T) {
assert.NilError(t, err)
err = sb2.rebuildDNS()
assert.NilError(t, err)
currRC, err = resolvconf.GetSpecific(sb2.config.resolvConfPath)
assert.NilError(t, err)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath)
assert.Check(t, is.DeepEqual([]string{"ndots:0"}, dnsOptionsList))
sb2.config.dnsOptionsList = []string{"ndots:-1"}
@@ -86,8 +87,6 @@ func TestDNSOptions(t *testing.T) {
assert.NilError(t, err)
err = sb2.rebuildDNS()
assert.NilError(t, err)
currRC, err = resolvconf.GetSpecific(sb2.config.resolvConfPath)
assert.NilError(t, err)
dnsOptionsList = resolvconf.GetOptions(currRC.Content)
dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath)
assert.Check(t, is.DeepEqual([]string{"ndots:0"}, dnsOptionsList))
}
+1 -2
View File
@@ -12,8 +12,7 @@ import (
"github.com/moby/moby/v2/errdefs"
)
// constants for the IP address type
// Deprecated: use the consts defined in github.com/docker/docker/libnetwork/resolvconf
// constants for the IP address type.
const (
IP = iota // IPv4 and IPv6
IPv4