Skip to content

Commit

Permalink
This add supports for systemd-resolved via
Browse files Browse the repository at this point in the history
agent.json by adding `"DNSResolverType": "systemd"`
to the linux platform config

[#187214132] bosh-agent systemd-resolved
  • Loading branch information
lnguyen committed Mar 21, 2024
1 parent 5d00e08 commit 581cae8
Show file tree
Hide file tree
Showing 17 changed files with 493 additions and 331 deletions.
6 changes: 4 additions & 2 deletions agent/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import (
boshdisk "github.com/cloudfoundry/bosh-agent/platform/disk"
boshnet "github.com/cloudfoundry/bosh-agent/platform/net"
bosharp "github.com/cloudfoundry/bosh-agent/platform/net/arp"
boshdnsresolver "github.com/cloudfoundry/bosh-agent/platform/net/dnsresolver"
boship "github.com/cloudfoundry/bosh-agent/platform/net/ip"
boshudev "github.com/cloudfoundry/bosh-agent/platform/udevdevice"
boshvitals "github.com/cloudfoundry/bosh-agent/platform/vitals"
Expand Down Expand Up @@ -1113,14 +1114,15 @@ var _ = Describe("bootstrap", func() {
interfaceConfigurationCreator := boshnet.NewInterfaceConfigurationCreator(logger)

interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{}
dnsValidator := boshnet.NewDNSValidator(fs)
logger = boshlog.NewLogger(boshlog.LevelNone)
kernelIPv6 := boshnet.NewKernelIPv6Impl(fs, runner, logger)
fakeMACAddressDetector = &netfakes.FakeMACAddressDetector{}
err := fs.WriteFileString("/etc/resolv.conf", "8.8.8.8 4.4.4.4")
Expect(err).NotTo(HaveOccurred())

ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, fakeMACAddressDetector, interfaceConfigurationCreator, interfaceAddrsProvider, dnsValidator, arping, kernelIPv6, logger)
dnsResolver := boshdnsresolver.NewResolveConfResolver(fs, runner)

ubuntuNetManager := boshnet.NewUbuntuNetManager(fs, runner, ipResolver, fakeMACAddressDetector, interfaceConfigurationCreator, interfaceAddrsProvider, dnsResolver, arping, kernelIPv6, logger)
ubuntuCertManager := boshcert.NewUbuntuCertManager(fs, runner, 1, logger)

monitRetryable := boshplatform.NewMonitRetryable(runner)
Expand Down
4 changes: 4 additions & 0 deletions platform/linux_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ type LinuxOptions struct {
// possible values: parted, "" (default is sfdisk if disk < 2TB, parted otherwise)
PartitionerType string

// Strategy for resolving DNS Resolvers
// possible values: systemd, ""
DNSResolverType string

// Regular expression specifying what part of volume ID to strip.
// possible values: valid RE2 regex e.g. "^vol-", "" (default is not to strip)
StripVolumeRegex string
Expand Down
9 changes: 5 additions & 4 deletions platform/net/centos_net_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"time"

bosharp "github.com/cloudfoundry/bosh-agent/platform/net/arp"
boshdnsresolver "github.com/cloudfoundry/bosh-agent/platform/net/dnsresolver"
boship "github.com/cloudfoundry/bosh-agent/platform/net/ip"
boshsettings "github.com/cloudfoundry/bosh-agent/settings"
bosherr "github.com/cloudfoundry/bosh-utils/errors"
Expand All @@ -27,7 +28,7 @@ type centosNetManager struct {
macAddressDetector MACAddressDetector
interfaceConfigurationCreator InterfaceConfigurationCreator
interfaceAddrsProvider boship.InterfaceAddressesProvider
dnsValidator DNSValidator
dnsResolver boshdnsresolver.DNSResolver
addressBroadcaster bosharp.AddressBroadcaster
logger boshlog.Logger
}
Expand All @@ -39,7 +40,7 @@ func NewCentosNetManager(
macAddressDetector MACAddressDetector,
interfaceConfigurationCreator InterfaceConfigurationCreator,
interfaceAddrsProvider boship.InterfaceAddressesProvider,
dnsValidator DNSValidator,
dnsResolver boshdnsresolver.DNSResolver,
addressBroadcaster bosharp.AddressBroadcaster,
logger boshlog.Logger,
) Manager {
Expand All @@ -50,7 +51,7 @@ func NewCentosNetManager(
macAddressDetector: macAddressDetector,
interfaceConfigurationCreator: interfaceConfigurationCreator,
interfaceAddrsProvider: interfaceAddrsProvider,
dnsValidator: dnsValidator,
dnsResolver: dnsResolver,
addressBroadcaster: addressBroadcaster,
logger: logger,
}
Expand Down Expand Up @@ -147,7 +148,7 @@ func (net centosNetManager) SetupNetworking(networks boshsettings.Networks, mbus
// This is an intentional asymmetry vs `ubuntu_net_manager.go`.
// See the comments at the top of this function for details.

err = net.dnsValidator.Validate(dnsServers)
err = net.dnsResolver.Validate(dnsServers)
if err != nil {
return bosherr.WrapError(err, "Validating dns configuration")
}
Expand Down
33 changes: 3 additions & 30 deletions platform/net/centos_net_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

. "github.com/cloudfoundry/bosh-agent/platform/net"
fakearp "github.com/cloudfoundry/bosh-agent/platform/net/arp/fakes"
fakednsresolver "github.com/cloudfoundry/bosh-agent/platform/net/dnsresolver/fakes"
boship "github.com/cloudfoundry/bosh-agent/platform/net/ip"
fakeip "github.com/cloudfoundry/bosh-agent/platform/net/ip/fakes"
"github.com/cloudfoundry/bosh-agent/platform/net/netfakes"
Expand Down Expand Up @@ -55,7 +56,7 @@ func describeCentosNetManager() {
fakeMACAddressDetector = &netfakes.FakeMACAddressDetector{}
interfaceConfigurationCreator = NewInterfaceConfigurationCreator(logger)
interfaceAddrsProvider = &fakeip.FakeInterfaceAddressesProvider{}
dnsValidator := NewDNSValidator(fs)
fakeDnsResolver := &fakednsresolver.FakeDNSResolver{}
addressBroadcaster = &fakearp.FakeAddressBroadcaster{}
netManager = NewCentosNetManager(
fs,
Expand All @@ -64,7 +65,7 @@ func describeCentosNetManager() {
fakeMACAddressDetector,
interfaceConfigurationCreator,
interfaceAddrsProvider,
dnsValidator,
fakeDnsResolver,
addressBroadcaster,
logger,
)
Expand Down Expand Up @@ -470,34 +471,6 @@ request subnet-mask, broadcast-address, time-offset, routers,
})
})

Context("when dns is not properly configured", func() {
BeforeEach(func() {
err := fs.WriteFileString("/etc/resolv.conf", "")
Expect(err).NotTo(HaveOccurred())
})

It("fails", func() {
staticNetwork = boshsettings.Network{
Type: "manual",
IP: "1.2.3.4",
Default: []string{"dns"},
DNS: []string{"8.8.8.8"},
Netmask: "255.255.255.0",
Gateway: "3.4.5.6",
Mac: "fake-static-mac-address",
}

stubInterfaces(map[string]boshsettings.Network{
"ethstatic": staticNetwork,
})

errCh := make(chan error)
err := netManager.SetupNetworking(boshsettings.Networks{"static-network": staticNetwork}, "", errCh)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Validating dns configuration"))
})
})

Context("when no MAC address is provided in the settings", func() {
var staticNetworkWithoutMAC boshsettings.Network

Expand Down
50 changes: 0 additions & 50 deletions platform/net/dns_validator.go

This file was deleted.

57 changes: 0 additions & 57 deletions platform/net/dns_validator_test.go

This file was deleted.

116 changes: 116 additions & 0 deletions platform/net/dnsresolver/dns_resolveconf_resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package dnsresolver

import (
"bytes"
"html/template"
gonet "net"
"path/filepath"
"strings"

bosherr "github.com/cloudfoundry/bosh-utils/errors"
boshsys "github.com/cloudfoundry/bosh-utils/system"
)

const (
resolvConfTemplate = `# Generated by bosh-agent
{{ range .DNSServers }}nameserver {{ . }}
{{ end }}`
)

type resolveConfResolver struct {
fs boshsys.FileSystem
cmdRunner boshsys.CmdRunner
}

func NewResolveConfResolver(
fs boshsys.FileSystem,
cmdRunner boshsys.CmdRunner,
) DNSResolver {
return &resolveConfResolver{
fs: fs,
cmdRunner: cmdRunner,
}
}

func (d *resolveConfResolver) Validate(dnsServers []string) error {
if len(dnsServers) == 0 {
return nil
}

resolvConfContents, err := d.fs.ReadFileString("/etc/resolv.conf")
if err != nil {
return bosherr.WrapError(err, "Reading /etc/resolv.conf")
}

for _, dnsServer := range dnsServers {
if strings.Contains(resolvConfContents, dnsServer) {
return nil
}

canonicalIP := gonet.ParseIP(dnsServer)

if canonicalIP != nil {
if strings.Contains(resolvConfContents, canonicalIP.String()) {
return nil
}
}
}

return bosherr.WrapError(err, "None of the DNS servers that were specified in the manifest were found in /etc/resolv.conf.")
}

func (d *resolveConfResolver) SetupDNS(dnsServers []string) error {
buffer := bytes.NewBuffer([]byte{})

t := template.Must(template.New("resolv-conf").Parse(resolvConfTemplate))

type dnsConfigArg struct {
DNSServers []string
}

dnsServersArg := dnsConfigArg{dnsServers}

err := t.Execute(buffer, dnsServersArg)
if err != nil {
return bosherr.WrapError(err, "Generating DNS config from template")
}

if len(dnsServers) > 0 { //nolint:nestif
// Write out base so that releases may overwrite head
err = d.fs.WriteFile("/etc/resolvconf/resolv.conf.d/base", buffer.Bytes())
if err != nil {
return bosherr.WrapError(err, "Writing to /etc/resolvconf/resolv.conf.d/base")
}
} else {
// For the first time before resolv.conf is symlinked to /run/...
// inherit possibly configured resolv.conf

targetPath, err := d.fs.ReadAndFollowLink("/etc/resolv.conf")
if err != nil {
return bosherr.WrapError(err, "Reading /etc/resolv.conf symlink")
}

expectedPath, err := filepath.Abs("/etc/resolv.conf")
if err != nil {
return bosherr.WrapError(err, "Resolving path to native OS")
}
if targetPath == expectedPath {
err := d.fs.CopyFile("/etc/resolv.conf", "/etc/resolvconf/resolv.conf.d/base")
if err != nil {
return bosherr.WrapError(err, "Copying /etc/resolv.conf for backwards compat")
}
}
}

err = d.fs.Symlink("/run/resolvconf/resolv.conf", "/etc/resolv.conf")
if err != nil {
return bosherr.WrapError(err, "Setting up /etc/resolv.conf symlink")
}

_, _, _, err = d.cmdRunner.RunCommand("resolvconf", "-u")
if err != nil {
return bosherr.WrapError(err, "Updating resolvconf")
}

return nil
}
Loading

0 comments on commit 581cae8

Please sign in to comment.