Skip to content

Commit 0c088ea

Browse files
committed
daemon: introduce support for cleaning environment
This introduces an `unsetEnvironment` flag for watchdog and notify functions to clear the relevant environment variables, aligning those to their native counterparts.
1 parent 831c9d5 commit 0c088ea

File tree

4 files changed

+77
-46
lines changed

4 files changed

+77
-46
lines changed

daemon/sdnotify.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ import (
2222
)
2323

2424
// SdNotify sends a message to the init daemon. It is common to ignore the error.
25+
// If `unsetEnvironment` is true, the environment variable `NOTIFY_SOCKET`
26+
// will be unconditionally unset.
27+
//
2528
// It returns one of the following:
2629
// (false, nil) - notification not supported (i.e. NOTIFY_SOCKET is unset)
2730
// (false, err) - notification supported, but failure happened (e.g. error connecting to NOTIFY_SOCKET or while sending data)
2831
// (true, nil) - notification supported, data has been sent
29-
func SdNotify(state string) (sent bool, err error) {
32+
func SdNotify(unsetEnvironment bool, state string) (sent bool, err error) {
3033
socketAddr := &net.UnixAddr{
3134
Name: os.Getenv("NOTIFY_SOCKET"),
3235
Net: "unixgram",
@@ -37,6 +40,13 @@ func SdNotify(state string) (sent bool, err error) {
3740
return false, nil
3841
}
3942

43+
if unsetEnvironment {
44+
err = os.Unsetenv("NOTIFY_SOCKET")
45+
}
46+
if err != nil {
47+
return false, err
48+
}
49+
4050
conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr)
4151
// Error connecting to NOTIFY_SOCKET
4252
if err != nil {

daemon/sdnotify_test.go

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
package daemon
1616

1717
import (
18+
"fmt"
1819
"io/ioutil"
1920
"net"
2021
"os"
@@ -23,9 +24,6 @@ import (
2324

2425
// TestSdNotify
2526
func TestSdNotify(t *testing.T) {
26-
notificationSupportedDataSent := "Notification supported, data sent"
27-
notificationSupportedFailure := "Notification supported, but failure happened"
28-
notificationNotSupported := "Notification not supported"
2927

3028
testDir, e := ioutil.TempDir("/tmp/", "test-")
3129
if e != nil {
@@ -43,33 +41,39 @@ func TestSdNotify(t *testing.T) {
4341
panic(e)
4442
}
4543

46-
// (true, nil) - notification supported, data has been sent
47-
e = os.Setenv("NOTIFY_SOCKET", notifySocket)
48-
if e != nil {
49-
panic(e)
50-
}
51-
sent, err := SdNotify(notificationSupportedDataSent)
52-
if !sent || err != nil {
53-
t.Errorf("TEST: %s FAILED", notificationSupportedDataSent)
54-
}
44+
tests := []struct {
45+
unsetEnv bool
46+
envSocket string
5547

56-
// (false, err) - notification supported, but failure happened
57-
e = os.Setenv("NOTIFY_SOCKET", testDir+"/not-exist.sock")
58-
if e != nil {
59-
panic(e)
60-
}
61-
sent, err = SdNotify(notificationSupportedFailure)
62-
if sent && err == nil {
63-
t.Errorf("TEST: %s FAILED", notificationSupportedFailure)
48+
wsent bool
49+
werr bool
50+
}{
51+
// (true, nil) - notification supported, data has been sent
52+
{false, notifySocket, true, false},
53+
// (false, err) - notification supported, but failure happened
54+
{true, testDir + "/missing.sock", false, true},
55+
// (false, nil) - notification not supported
56+
{true, "", false, false},
6457
}
6558

66-
// (false, nil) - notification not supported
67-
e = os.Unsetenv("NOTIFY_SOCKET")
68-
if e != nil {
69-
panic(e)
70-
}
71-
sent, err = SdNotify(notificationNotSupported)
72-
if sent || err != nil {
73-
t.Errorf("TEST: %s FAILED", notificationNotSupported)
59+
for i, tt := range tests {
60+
must(os.Unsetenv("NOTIFY_SOCKET"))
61+
if tt.envSocket != "" {
62+
must(os.Setenv("NOTIFY_SOCKET", tt.envSocket))
63+
}
64+
sent, err := SdNotify(tt.unsetEnv, fmt.Sprintf("TestSdNotify test message #%d", i))
65+
66+
if sent != tt.wsent {
67+
t.Errorf("#%d: expected send result %t, got %t", i, tt.wsent, sent)
68+
}
69+
if tt.werr && err == nil {
70+
t.Errorf("#%d: want non-nil err, got nil", i)
71+
} else if !tt.werr && err != nil {
72+
t.Errorf("#%d: want nil err, got %v", i, err)
73+
}
74+
if tt.unsetEnv && tt.envSocket != "" && os.Getenv("NOTIFY_SOCKET") != "" {
75+
t.Errorf("#%d: environment variable not cleaned up", i)
76+
}
77+
7478
}
7579
}

daemon/watchdog.go

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,28 @@ import (
2323

2424
// SdWatchdogEnabled return watchdog information for a service.
2525
// Process should send daemon.SdNotify("WATCHDOG=1") every time / 2.
26+
// If `unsetEnvironment` is true, the environment variables `WATCHDOG_USEC`
27+
// and `WATCHDOG_PID` will be unconditionally unset.
2628
//
2729
// It returns one of the following:
2830
// (0, nil) - watchdog isn't enabled or we aren't the watched PID.
2931
// (0, err) - an error happened (e.g. error converting time).
3032
// (time, nil) - watchdog is enabled and we can send ping.
3133
// time is delay before inactive service will be killed.
32-
func SdWatchdogEnabled() (time.Duration, error) {
34+
func SdWatchdogEnabled(unsetEnvironment bool) (time.Duration, error) {
3335
wusec := os.Getenv("WATCHDOG_USEC")
36+
wpid := os.Getenv("WATCHDOG_PID")
37+
if unsetEnvironment {
38+
wusecErr := os.Unsetenv("WATCHDOG_USEC")
39+
wpidErr := os.Unsetenv("WATCHDOG_PID")
40+
if wusecErr != nil {
41+
return 0, wusecErr
42+
}
43+
if wpidErr != nil {
44+
return 0, wpidErr
45+
}
46+
}
47+
3448
if wusec == "" {
3549
return 0, nil
3650
}
@@ -43,7 +57,6 @@ func SdWatchdogEnabled() (time.Duration, error) {
4357
}
4458
interval := time.Duration(s) * time.Microsecond
4559

46-
wpid := os.Getenv("WATCHDOG_PID")
4760
if wpid == "" {
4861
return interval, nil
4962
}

daemon/watchdog_test.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,29 +30,30 @@ func must(err error) {
3030
func TestSdWatchdogEnabled(t *testing.T) {
3131
mypid := strconv.Itoa(os.Getpid())
3232
tests := []struct {
33-
usec string // empty => unset
34-
pid string // empty => unset
33+
usec string // empty => unset
34+
pid string // empty => unset
35+
unsetEnv bool // arbitrarily set across testcases
3536

3637
werr bool
3738
wdelay time.Duration
3839
}{
3940
// Success cases
40-
{"100", mypid, false, 100 * time.Microsecond},
41-
{"50", mypid, false, 50 * time.Microsecond},
42-
{"1", mypid, false, 1 * time.Microsecond},
43-
{"1", "", false, 1 * time.Microsecond},
41+
{"100", mypid, true, false, 100 * time.Microsecond},
42+
{"50", mypid, true, false, 50 * time.Microsecond},
43+
{"1", mypid, false, false, 1 * time.Microsecond},
44+
{"1", "", true, false, 1 * time.Microsecond},
4445

4546
// No-op cases
46-
{"", mypid, false, 0}, // WATCHDOG_USEC not set
47-
{"1", "0", false, 0}, // WATCHDOG_PID doesn't match
48-
{"", "", false, 0}, // Both not set
47+
{"", mypid, true, false, 0}, // WATCHDOG_USEC not set
48+
{"1", "0", false, false, 0}, // WATCHDOG_PID doesn't match
49+
{"", "", true, false, 0}, // Both not set
4950

5051
// Failure cases
51-
{"-1", mypid, true, 0}, // Negative USEC
52-
{"string", "1", true, 0}, // Non-integer USEC value
53-
{"1", "string", true, 0}, // Non-integer PID value
54-
{"stringa", "stringb", true, 0}, // E v e r y t h i n g
55-
{"-10239", "-eleventythree", true, 0}, // i s w r o n g
52+
{"-1", mypid, true, true, 0}, // Negative USEC
53+
{"string", "1", false, true, 0}, // Non-integer USEC value
54+
{"1", "string", true, true, 0}, // Non-integer PID value
55+
{"stringa", "stringb", false, true, 0}, // E v e r y t h i n g
56+
{"-10239", "-eleventythree", true, true, 0}, // i s w r o n g
5657
}
5758

5859
for i, tt := range tests {
@@ -67,7 +68,7 @@ func TestSdWatchdogEnabled(t *testing.T) {
6768
must(os.Unsetenv("WATCHDOG_PID"))
6869
}
6970

70-
delay, err := SdWatchdogEnabled()
71+
delay, err := SdWatchdogEnabled(tt.unsetEnv)
7172

7273
if tt.werr && err == nil {
7374
t.Errorf("#%d: want non-nil err, got nil", i)
@@ -77,5 +78,8 @@ func TestSdWatchdogEnabled(t *testing.T) {
7778
if tt.wdelay != delay {
7879
t.Errorf("#%d: want delay=%d, got %d", i, tt.wdelay, delay)
7980
}
81+
if tt.unsetEnv && (os.Getenv("WATCHDOG_PID") != "" || os.Getenv("WATCHDOG_USEC") != "") {
82+
t.Errorf("#%d: environment variables not cleaned up", i)
83+
}
8084
}
8185
}

0 commit comments

Comments
 (0)