Merge pull request #49575 from thaJeztah/refactor_resolvconf_build

libnetwork/resolvconf: re-implement "Build" with the new libnetwork/internal/resolvconf code
This commit is contained in:
Sebastiaan van Stijn
2025-03-05 13:17:47 +01:00
committed by GitHub
2 changed files with 54 additions and 27 deletions

View File

@@ -5,7 +5,6 @@ import (
"bytes"
"net/netip"
"os"
"strings"
"github.com/docker/docker/libnetwork/internal/resolvconf"
"github.com/opencontainers/go-digest"
@@ -127,31 +126,33 @@ func GetOptions(resolvConf []byte) []string {
//
// Note that the resolv.conf file is written, but the hash file is not.
func Build(path string, nameservers, dnsSearch, dnsOptions []string) (*File, error) {
content := bytes.NewBuffer(nil)
if len(dnsSearch) > 0 {
if searchString := strings.Join(dnsSearch, " "); strings.Trim(searchString, " ") != "." {
if _, err := content.WriteString("search " + searchString + "\n"); err != nil {
return nil, err
}
}
}
for _, dns := range nameservers {
if _, err := content.WriteString("nameserver " + dns + "\n"); err != nil {
var ns []netip.Addr
for _, addr := range nameservers {
ipAddr, err := netip.ParseAddr(addr)
if err != nil {
return nil, err
}
ns = append(ns, ipAddr)
}
if len(dnsOptions) > 0 {
if optsString := strings.Join(dnsOptions, " "); strings.Trim(optsString, " ") != "" {
if _, err := content.WriteString("options " + optsString + "\n"); err != nil {
return nil, err
}
}
}
rc := resolvconf.ResolvConf{}
rc.OverrideNameServers(ns)
rc.OverrideSearch(dnsSearch)
rc.OverrideOptions(dnsOptions)
if err := os.WriteFile(path, content.Bytes(), 0o644); err != nil {
content, err := rc.Generate(false)
if err != nil {
return nil, err
}
hash := digest.FromBytes(content.Bytes())
return &File{Content: content.Bytes(), Hash: []byte(hash)}, nil
// 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
}

View File

@@ -289,6 +289,16 @@ func strSlicesEqual(a, b []string) bool {
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) {
tmpDir := t.TempDir()
file, err := os.CreateTemp(tmpDir, "")
@@ -296,12 +306,18 @@ func TestBuild(t *testing.T) {
t.Fatal(err)
}
f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{"opt1"})
f, err := Build(file.Name(), []string{testNS1, testNS2, testNS3}, []string{"search1"}, []string{"opt1"})
if err != nil {
t.Fatal(err)
}
const expected = "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"
const expected = `nameserver 192.0.2.1
nameserver 2001:db8::1
nameserver 203.0.113.3
search search1
options opt1
`
if !bytes.Equal(f.Content, []byte(expected)) {
t.Errorf("Expected to find '%s' got '%s'", expected, f.Content)
}
@@ -321,12 +337,17 @@ func TestBuildWithZeroLengthDomainSearch(t *testing.T) {
t.Fatal(err)
}
f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"."}, []string{"opt1"})
f, err := Build(file.Name(), []string{testNS1, testNS2, testNS3}, []string{"."}, []string{"opt1"})
if err != nil {
t.Fatal(err)
}
const expected = "nameserver ns1\nnameserver ns2\nnameserver ns3\noptions opt1\n"
const expected = `nameserver 192.0.2.1
nameserver 2001:db8::1
nameserver 203.0.113.3
options opt1
`
if !bytes.Equal(f.Content, []byte(expected)) {
t.Errorf("Expected to find '%s' got '%s'", expected, f.Content)
}
@@ -346,12 +367,17 @@ func TestBuildWithNoOptions(t *testing.T) {
t.Fatal(err)
}
f, err := Build(file.Name(), []string{"ns1", "ns2", "ns3"}, []string{"search1"}, []string{})
f, err := Build(file.Name(), []string{testNS1, testNS2, testNS3}, []string{"search1"}, []string{})
if err != nil {
t.Fatal(err)
}
const expected = "search search1\nnameserver ns1\nnameserver ns2\nnameserver ns3\n"
const expected = `nameserver 192.0.2.1
nameserver 2001:db8::1
nameserver 203.0.113.3
search search1
`
if !bytes.Equal(f.Content, []byte(expected)) {
t.Errorf("Expected to find '%s' got '%s'", expected, f.Content)
}