Skip to content

Commit d7387fd

Browse files
authored
Merge pull request #209 from guilhem/watchdog
daemon: add watchdog checker
2 parents d659fb6 + c7e8365 commit d7387fd

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

daemon/watchdog.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2016 CoreOS, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package daemon
16+
17+
import (
18+
"fmt"
19+
"os"
20+
"strconv"
21+
"time"
22+
)
23+
24+
// SdWatchdogEnabled return watchdog information for a service.
25+
// Process should send daemon.SdNotify("WATCHDOG=1") every time / 2.
26+
//
27+
// It returns one of the following:
28+
// (0, nil) - watchdog isn't enabled or we aren't the watched PID.
29+
// (0, err) - an error happened (e.g. error converting time).
30+
// (time, nil) - watchdog is enabled and we can send ping.
31+
// time is delay before inactive service will be killed.
32+
func SdWatchdogEnabled() (time.Duration, error) {
33+
wusec := os.Getenv("WATCHDOG_USEC")
34+
if wusec == "" {
35+
return 0, nil
36+
}
37+
s, err := strconv.Atoi(wusec)
38+
if err != nil {
39+
return 0, fmt.Errorf("error converting WATCHDOG_USEC: %s", err)
40+
}
41+
if s <= 0 {
42+
return 0, fmt.Errorf("error WATCHDOG_USEC must a positive number")
43+
}
44+
45+
wpid := os.Getenv("WATCHDOG_PID")
46+
if wpid == "" {
47+
return 0, nil
48+
}
49+
p, err := strconv.Atoi(wpid)
50+
if err != nil {
51+
return 0, fmt.Errorf("error converting WATCHDOG_PID: %s", err)
52+
}
53+
if os.Getpid() != p {
54+
return 0, nil
55+
}
56+
57+
return time.Duration(s) * time.Microsecond, nil
58+
}

daemon/watchdog_test.go

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
// Copyright 2016 CoreOS, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package daemon
16+
17+
import (
18+
"os"
19+
"strconv"
20+
"testing"
21+
"time"
22+
)
23+
24+
func must(err error) {
25+
if err != nil {
26+
panic(err)
27+
}
28+
}
29+
30+
func TestSdWatchdogEnabled(t *testing.T) {
31+
mypid := strconv.Itoa(os.Getpid())
32+
tests := []struct {
33+
usec string // empty => unset
34+
pid string // empty => unset
35+
36+
werr bool
37+
wdelay time.Duration
38+
}{
39+
// Success cases
40+
{"100", mypid, false, 100 * time.Microsecond},
41+
{"50", mypid, false, 50 * time.Microsecond},
42+
{"1", mypid, false, 1 * time.Microsecond},
43+
44+
// No-op cases
45+
{"", mypid, false, 0}, // WATCHDOG_USEC not set
46+
{"1", "", false, 0}, // WATCHDOG_PID not set
47+
{"1", "0", false, 0}, // WATCHDOG_PID doesn't match
48+
{"", "", false, 0}, // Both not set
49+
50+
// 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
56+
}
57+
58+
for i, tt := range tests {
59+
if tt.usec != "" {
60+
must(os.Setenv("WATCHDOG_USEC", tt.usec))
61+
} else {
62+
must(os.Unsetenv("WATCHDOG_USEC"))
63+
}
64+
if tt.pid != "" {
65+
must(os.Setenv("WATCHDOG_PID", tt.pid))
66+
} else {
67+
must(os.Unsetenv("WATCHDOG_PID"))
68+
}
69+
70+
delay, err := SdWatchdogEnabled()
71+
72+
if tt.werr && err == nil {
73+
t.Errorf("#%d: want non-nil err, got nil", i)
74+
} else if !tt.werr && err != nil {
75+
t.Errorf("#%d: want nil err, got %v", i, err)
76+
}
77+
if tt.wdelay != delay {
78+
t.Errorf("#%d: want delay=%d, got %d", i, tt.wdelay, delay)
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)