Skip to content

Commit b0ca20f

Browse files
committed
Send SIGUSR1 to dnsmasq periodically
This adds a feature flag --logInterval for periodic triggering dnsmasq to log its statistics by sending SIGUSR1 to it. The new motivation for adding this feature comes from the recently added dnsmasq flag --max-tcp-connections and the related statistics of TCP connection utilisation being added to the log output triggered by SIGUSR1.
1 parent c0fa2d1 commit b0ca20f

File tree

4 files changed

+70
-3
lines changed

4 files changed

+70
-3
lines changed

cmd/dnsmasq-nanny/main.go

+4
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ var (
3737
RunNannyOpts: dnsmasq.RunNannyOpts{
3838
DnsmasqExec: "/usr/sbin/dnsmasq",
3939
RestartOnChange: false,
40+
LogInterval: time.Duration(0),
4041
},
4142
configDir: "/etc/k8s/dns/dnsmasq-nanny",
4243
syncInterval: 10 * time.Second,
@@ -69,6 +70,9 @@ Any arguments given after "--" will be passed directly to dnsmasq itself.
6970
"interval to check for configuration updates")
7071
flag.StringVar(&opts.kubednsServer, "kubednsServer", opts.kubednsServer,
7172
"local kubedns instance address for non-IP name resolution")
73+
flag.DurationVar(&opts.LogInterval, "logInterval",
74+
opts.LogInterval,
75+
"interval to send SIGUSR1 to dnsmasq which triggers statistics logging")
7276
klog.InitFlags(nil)
7377
flag.Parse()
7478
}

pkg/dnsmasq/nanny.go

+30-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ import (
2424
"net"
2525
"os/exec"
2626
"strings"
27+
"syscall"
28+
"time"
2729

2830
"k8s.io/dns/pkg/dns/config"
2931
"k8s.io/klog/v2"
@@ -176,7 +178,6 @@ func (n *Nanny) Kill() error {
176178
}
177179

178180
if err := n.cmd.Process.Kill(); err != nil {
179-
klog.Errorf("Error killing dnsmasq: %v", err)
180181
return err
181182
}
182183

@@ -185,6 +186,17 @@ func (n *Nanny) Kill() error {
185186
return nil
186187
}
187188

189+
// Send SIGUSR1 to dnsmasq (which makes dnsmasq log statistics).
190+
func (n *Nanny) SendSIGUSR1() error {
191+
if n.cmd == nil {
192+
return fmt.Errorf("Process is not running")
193+
}
194+
if err := n.cmd.Process.Signal(syscall.SIGUSR1); err != nil {
195+
return err
196+
}
197+
return nil
198+
}
199+
188200
// RunNannyOpts for running the nanny.
189201
type RunNannyOpts struct {
190202
// Location of the dnsmasq executable.
@@ -193,6 +205,8 @@ type RunNannyOpts struct {
193205
DnsmasqArgs []string
194206
// Restart the daemon on ConfigMap changes.
195207
RestartOnChange bool
208+
// Interval for triggering dnsmasq to log its statistics by sending SIGUSR1.
209+
LogInterval time.Duration
196210
}
197211

198212
// RunNanny runs the nanny and handles configuration updates.
@@ -211,6 +225,11 @@ func RunNanny(sync config.Sync, opts RunNannyOpts, kubednsServer string) {
211225
klog.Fatalf("Could not start dnsmasq with initial configuration: %v", err)
212226
}
213227

228+
logChannel := make(<-chan time.Time)
229+
if opts.LogInterval != 0 {
230+
logChannel = time.NewTicker(opts.LogInterval).C
231+
}
232+
214233
configChan := sync.Periodic()
215234

216235
for {
@@ -222,14 +241,22 @@ func RunNanny(sync config.Sync, opts RunNannyOpts, kubednsServer string) {
222241
case currentConfig = <-configChan:
223242
if opts.RestartOnChange {
224243
klog.V(0).Infof("Restarting dnsmasq with new configuration")
225-
nanny.Kill()
244+
if err := nanny.Kill(); err != nil {
245+
klog.Errorf("Error killing dnsmasq: %v", err)
246+
}
226247
nanny = &Nanny{Exec: opts.DnsmasqExec}
227248
nanny.Configure(opts.DnsmasqArgs, currentConfig, kubednsServer)
228-
nanny.Start()
249+
if err := nanny.Start(); err != nil {
250+
klog.Errorf("Could not start dnsmasq with new configuration: %v", err)
251+
}
229252
} else {
230253
klog.V(2).Infof("Not restarting dnsmasq (--restartDnsmasq=false)")
231254
}
232255
break
256+
case <-logChannel:
257+
if err := nanny.SendSIGUSR1(); err != nil {
258+
klog.Warningf("Error sending SIGUSR1 to dnsmasq: %v", err)
259+
}
233260
}
234261
}
235262
}

pkg/dnsmasq/nanny_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,24 @@ func TestNannyLifecycle(t *testing.T) {
163163
time.Sleep(250 * time.Millisecond)
164164
gomega.Expect(nanny.Kill()).To(gomega.Succeed())
165165
gomega.Expect(nanny.Kill()).NotTo(gomega.Succeed())
166+
167+
// Send SIGUSR1.
168+
nanny = &Nanny{Exec: mockDnsmasq}
169+
nanny.Configure(
170+
[]string{"--trapTwice"},
171+
&config.Config{},
172+
kubednsServer)
173+
gomega.Expect(nanny.Start()).To(gomega.Succeed())
174+
time.Sleep(time.Second)
175+
gomega.Expect(nanny.SendSIGUSR1()).To(gomega.Succeed())
176+
time.Sleep(250 * time.Millisecond)
177+
running := true // Dnsmasq reacts on SIGUSR1 and continues.
178+
select {
179+
case _ = <-nanny.ExitChannel:
180+
running = false
181+
default:
182+
}
183+
gomega.Expect(running).To(gomega.BeTrue())
184+
gomega.Expect(nanny.SendSIGUSR1()).To(gomega.Succeed()) // mockDnsmasq with --trapTwice successfully exits after receiving the second SIGUSR1.
185+
gomega.Expect(<-nanny.ExitChannel).To(gomega.Succeed())
166186
}

test/fixtures/mock-dnsmasq.sh

+16
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,21 @@ sleepThenError() {
3737
exit 1
3838
}
3939

40+
COUNT=0
41+
exitOnSecondCall() {
42+
: $((COUNT+=1))
43+
echo "Function call no ${COUNT}"
44+
if [ $COUNT -ge 2 ]; then
45+
exit 0
46+
fi
47+
}
48+
49+
trapTwice() {
50+
trap exitOnSecondCall USR1
51+
echo "Trap registered"
52+
runForever
53+
}
54+
4055
ARGS="$*"
4156
RUN=
4257

@@ -50,6 +65,7 @@ while [ ! -z "$1" ]; do
5065
--exitWithSuccess) RUN=exitWithSuccess;;
5166
--runForever) RUN=runForever;;
5267
--sleepThenError) RUN=sleepThenError;;
68+
--trapTwice) RUN=trapTwice;;
5369
esac
5470
shift
5571
done

0 commit comments

Comments
 (0)