Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions agent/bootstrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ func (boot bootstrap) Run() (err error) { //nolint:gocyclo
return bosherr.WrapError(err, "Setting up hostname")
}

if err = boot.platform.SetupSystemdResolved(settings.Env.Bosh.SystemdResolved); err != nil {
return bosherr.WrapError(err, "Setting up systemd-resolved")
Comment thread
neddp marked this conversation as resolved.
Resolved
}

if err = boot.platform.SetupNetworking(settings.Networks, settings.GetMbusURLs()); err != nil {
return bosherr.WrapError(err, "Setting up networking")
}
Expand Down
40 changes: 40 additions & 0 deletions agent/bootstrap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,46 @@ var _ = Describe("bootstrap", func() {
Expect(platform.SetupHostnameArgsForCall(0)).To(Equal("foo-bar-baz-123"))
})

It("forwards the systemd-resolved settings to the platform", func() {
settingsService.Settings.Env.Bosh.SystemdResolved = boshsettings.SystemdResolvedSettings{Cache: "no-negative"}

err := bootstrap()
Expect(err).NotTo(HaveOccurred())
Expect(platform.SetupSystemdResolvedCallCount()).To(Equal(1))
Expect(platform.SetupSystemdResolvedArgsForCall(0)).To(Equal(boshsettings.SystemdResolvedSettings{Cache: "no-negative"}))
})

It("calls SetupSystemdResolved before SetupNetworking", func() {
var resolvedOrder, networkingOrder int
callIndex := 0
platform.SetupSystemdResolvedStub = func(_ boshsettings.SystemdResolvedSettings) error {
callIndex++
resolvedOrder = callIndex
return nil
}
platform.SetupNetworkingStub = func(_ boshsettings.Networks, _ []string) error {
callIndex++
networkingOrder = callIndex
return nil
}

err := bootstrap()
Expect(err).NotTo(HaveOccurred())
Expect(resolvedOrder).To(BeNumerically("<", networkingOrder))
})

Context("when setting up systemd-resolved fails", func() {
BeforeEach(func() {
platform.SetupSystemdResolvedReturns(errors.New("fake-systemd-resolved-err"))
})

It("returns an error", func() {
err := bootstrap()
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("fake-systemd-resolved-err"))
})
})

It("fetches initial settings", func() {
err := bootstrap()
Expect(err).NotTo(HaveOccurred())
Expand Down
4 changes: 4 additions & 0 deletions platform/dummy_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ func (p dummyPlatform) SetupHostname(hostname string) (err error) {
return
}

func (p dummyPlatform) SetupSystemdResolved(_ boshsettings.SystemdResolvedSettings) error {
return nil
}

func (p dummyPlatform) SetupNetworking(networks boshsettings.Networks, mbus []string) (err error) {
return
}
Expand Down
4 changes: 4 additions & 0 deletions platform/linux_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@ func (p linux) GetAuditLogger() AuditLogger {
return p.auditLogger
}

func (p linux) SetupSystemdResolved(resolved boshsettings.SystemdResolvedSettings) error {
return p.netManager.SetupSystemdResolved(resolved)
}

func (p linux) SetupNetworking(networks boshsettings.Networks, mbus []string) (err error) {
return p.netManager.SetupNetworking(networks, mbus, nil)
}
Expand Down
4 changes: 4 additions & 0 deletions platform/net/dnsresolver/dns_resolveconf_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (

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

boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
)

const (
Expand Down Expand Up @@ -59,6 +61,8 @@ func (d *resolveConfResolver) Validate(dnsServers []string) error {
return bosherr.WrapError(err, "None of the DNS servers that were specified in the manifest were found in /etc/resolv.conf.")
}

func (d *resolveConfResolver) SetupSystemdResolved(_ boshsettings.SystemdResolvedSettings) {}

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

Expand Down
7 changes: 6 additions & 1 deletion platform/net/dnsresolver/dns_resolver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package dnsresolver

import (
boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
)

type DNSResolver interface {
Validate([]string) error
SetupDNS([]string) error
SetupDNS(dnsServers []string) error
SetupSystemdResolved(boshsettings.SystemdResolvedSettings)
}
48 changes: 30 additions & 18 deletions platform/net/dnsresolver/dns_systemd_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,31 @@ package dnsresolver

import (
"bytes"
"html/template"
"fmt"
gonet "net"
"strings"

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

const (
systemdResolvedTemplate = `# Generated by bosh-agent
[Resolve]
DNS={{ range . }}{{ . }}{{ " " -}}
{{ end }}`
boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
)

// defaultCacheMode preserves the behaviour baked into the stemcell
// (bosh-linux-stemcell-builder enables negative caching) when the operator
// does not set env.bosh.systemd_resolved.cache.
const defaultCacheMode = "yes"

var validCacheModes = map[string]struct{}{
"yes": {},
"no": {},
"no-negative": {},
}

type systemdResolver struct {
fs boshsys.FileSystem
cmdRunner boshsys.CmdRunner
resolved boshsettings.SystemdResolvedSettings
}

func NewSystemdResolver(
Expand Down Expand Up @@ -58,24 +65,29 @@ func (d *systemdResolver) Validate(dnsServers []string) error {
return bosherr.WrapError(err, "None of the DNS servers that were specified in the manifest were found in /etc/systemd/resolved.conf.d/10-bosh.conf.")
}

func (d *systemdResolver) SetupSystemdResolved(resolved boshsettings.SystemdResolvedSettings) {
d.resolved = resolved
}

func (d *systemdResolver) SetupDNS(dnsServers []string) error {
// mkdir /etc/systemd/resolved.conf.d/
// create /etc/systemd/resolved.conf.d/10-bosh.conf
// contents (if your dns Servers are 1.1.1.1 and 8.8.8.8):
// DNS=8.8.8.8 1.1.1.1
if len(dnsServers) == 0 {
return nil
cacheMode := d.resolved.Cache
if cacheMode == "" {
cacheMode = defaultCacheMode
}
if _, ok := validCacheModes[cacheMode]; !ok {
return bosherr.Errorf("Invalid systemd-resolved cache mode %q (expected yes, no, or no-negative)", cacheMode)
}

var buffer bytes.Buffer
t := template.Must(template.New("resolv-conf").Parse(systemdResolvedTemplate))
err := t.Execute(&buffer, dnsServers)
if err != nil {
return bosherr.WrapError(err, "Generating DNS config from template")
buffer.WriteString("# Generated by bosh-agent\n[Resolve]\n")
if len(dnsServers) > 0 {
fmt.Fprintf(&buffer, "DNS=%s\n", strings.Join(dnsServers, " "))
}
fmt.Fprintf(&buffer, "Cache=%s\n", cacheMode)
Comment thread
neddp marked this conversation as resolved.
Resolved

// Create the directory; it doesn't exist on a vanilla Noble install
dirPath := "/etc/systemd/resolved.conf.d/"
err = d.fs.MkdirAll(dirPath, 0755)
err := d.fs.MkdirAll(dirPath, 0755)
if err != nil {
return bosherr.WrapError(err, "Creating directory "+dirPath)
}
Expand Down
42 changes: 36 additions & 6 deletions platform/net/dnsresolver/dns_systemd_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
. "github.com/onsi/gomega"

. "github.com/cloudfoundry/bosh-agent/v2/platform/net/dnsresolver"
boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
)

var _ = Describe("systemdConfResolver", func() {
Expand Down Expand Up @@ -57,26 +58,55 @@ var _ = Describe("systemdConfResolver", func() {
})

Context("when there are configured DNS servers", func() {
It("writes DNS to /etc/systemd/resolved.conf.d/10-bosh.conf", func() {
It("writes DNS and the default cache mode to /etc/systemd/resolved.conf.d/10-bosh.conf", func() {
err := systemdResolver.SetupDNS([]string{"8.8.8.8", "9.9.9.9"})
Expect(err).ToNot(HaveOccurred())

resolvConfBase := fs.GetFileTestStat("/etc/systemd/resolved.conf.d/10-bosh.conf")
Expect(resolvConfBase).ToNot(BeNil())

expectedResolvConfBase := `# Generated by bosh-agent
Expect(resolvConfBase.StringContents()).To(Equal(`# Generated by bosh-agent
[Resolve]
DNS=8.8.8.8 9.9.9.9`
Expect(resolvConfBase.StringContents()).To(ContainSubstring(expectedResolvConfBase))
DNS=8.8.8.8 9.9.9.9
Cache=yes
`))
Expect(cmdRunner.RunCommands[0]).To(Equal([]string{"systemctl", "restart", "systemd-resolved"}))
})

It("honors the operator-provided cache mode", func() {
systemdResolver.SetupSystemdResolved(boshsettings.SystemdResolvedSettings{Cache: "no-negative"})
err := systemdResolver.SetupDNS([]string{"8.8.8.8"})
Expect(err).ToNot(HaveOccurred())

resolvConfBase := fs.GetFileTestStat("/etc/systemd/resolved.conf.d/10-bosh.conf")
Expect(resolvConfBase).ToNot(BeNil())
Expect(resolvConfBase.StringContents()).To(Equal(`# Generated by bosh-agent
[Resolve]
DNS=8.8.8.8
Cache=no-negative
`))
})
})

Context("when no DNS servers are configured", func() {
It("return nil", func() {
It("still writes the cache mode and returns nil", func() {
err := systemdResolver.SetupDNS([]string{})
Expect(err).NotTo(HaveOccurred())

resolvConfBase := fs.GetFileTestStat("/etc/systemd/resolved.conf.d/10-bosh.conf")
Expect(resolvConfBase).ToNot(BeNil())
Expect(resolvConfBase.StringContents()).To(Equal(`# Generated by bosh-agent
[Resolve]
Cache=yes
`))
})
})

Context("when the cache mode is invalid", func() {
It("returns an error", func() {
systemdResolver.SetupSystemdResolved(boshsettings.SystemdResolvedSettings{Cache: "bogus"})
err := systemdResolver.SetupDNS([]string{"8.8.8.8"})
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("Invalid systemd-resolved cache mode"))
})
})
})
9 changes: 9 additions & 0 deletions platform/net/dnsresolver/fakes/fake_dns_resolver.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
package fakes

import (
boshsettings "github.com/cloudfoundry/bosh-agent/v2/settings"
)

type FakeDNSResolver struct {
SetupSystemdResolvedConfig boshsettings.SystemdResolvedSettings
}

func (f *FakeDNSResolver) Validate(dnsServers []string) error {
Expand All @@ -10,3 +15,7 @@ func (f *FakeDNSResolver) Validate(dnsServers []string) error {
func (f *FakeDNSResolver) SetupDNS(dnsServers []string) error {
return nil
}

func (f *FakeDNSResolver) SetupSystemdResolved(resolved boshsettings.SystemdResolvedSettings) {
f.SetupSystemdResolvedConfig = resolved
}
8 changes: 8 additions & 0 deletions platform/net/fakes/fake_net_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ type FakeManager struct {
SetupNetworkingNetworks boshsettings.Networks
SetupNetworkingErr error

SetupSystemdResolvedConfig boshsettings.SystemdResolvedSettings
SetupSystemdResolvedErr error

SetupIPv6Config boshsettings.IPv6
SetupIPv6StopCh <-chan struct{}
SetupIPv6Err error
Expand All @@ -27,6 +30,11 @@ func (net *FakeManager) SetupIPv6(config boshsettings.IPv6, stopCh <-chan struct
return net.SetupIPv6Err
}

func (net *FakeManager) SetupSystemdResolved(resolved boshsettings.SystemdResolvedSettings) error {
net.SetupSystemdResolvedConfig = resolved
return net.SetupSystemdResolvedErr
}

func (net *FakeManager) SetupNetworking(networks boshsettings.Networks, mbus []string, errCh chan error) error {
net.SetupNetworkingNetworks = networks
return net.SetupNetworkingErr
Expand Down
1 change: 1 addition & 0 deletions platform/net/net_manager_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ type Manager interface {
GetConfiguredNetworkInterfaces() ([]string, error)

SetupIPv6(boshsettings.IPv6, <-chan struct{}) error
SetupSystemdResolved(boshsettings.SystemdResolvedSettings) error
}
5 changes: 5 additions & 0 deletions platform/net/ubuntu_net_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ func (net UbuntuNetManager) SetupIPv6(config boshsettings.IPv6, stopCh <-chan st
return nil
}

func (net UbuntuNetManager) SetupSystemdResolved(resolved boshsettings.SystemdResolvedSettings) error {
net.dnsResolver.SetupSystemdResolved(resolved)
return nil
}

func (net UbuntuNetManager) SetupNetworking(networks boshsettings.Networks, mbus []string, errCh chan error) error {
if networks.IsPreconfigured() {
// Note in this case IPs are not broadcast
Expand Down
4 changes: 4 additions & 0 deletions platform/net/windows_net_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ func (net WindowsNetManager) setupNetworkInterfaces(networks boshsettings.Networ
return nil
}

func (net WindowsNetManager) SetupSystemdResolved(_ boshsettings.SystemdResolvedSettings) error {
return nil
}

func (net WindowsNetManager) SetupNetworking(networks boshsettings.Networks, mbus []string, errCh chan error) error {
if err := net.setupNetworkInterfaces(networks); err != nil {
return bosherr.WrapError(err, "setting up network interfaces")
Expand Down
1 change: 1 addition & 0 deletions platform/platform_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type Platform interface {
SetupBoshSettingsDisk() (err error)
SetupIPv6(boshsettings.IPv6) error
SetupHostname(hostname string) (err error)
SetupSystemdResolved(boshsettings.SystemdResolvedSettings) error
SetupNetworking(networks boshsettings.Networks, mbus []string) (err error)
SetupLogrotate(groupName, basePath, size string) (err error)
SetTimeWithNtpServers(servers []string) (err error)
Expand Down
Loading
Loading