-
Notifications
You must be signed in to change notification settings - Fork 309
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
daemon: add SdNotifyMonotonicUsec helper function
The synchronized service reload protocol added in systemd version 253 requires that the service provides a MONOTONIC_USEC field alongside the RELOADING=1 notification message for synchronization purposes. The value carried in this field must be the system CLOCK_MONOTONIC timestamp at the time the notification message was generated as systemd compares it to other CLOCK_MONOTONIC timestamps taken by pid1. While the Go standard library does utilize CLOCK_MONOTONIC in the implementation of package "time", the absolute monotonic timestamps in time.Time values are not made available to programmers. Users familiar with idiomatic usage of monotonic timestamps in Go might (incorrectly) try to implement MONOTONIC_USEC using process-relative monotonic timestamps, like so: var processStart = time.Now() func NotifyReloadingINCORRECT() { ts := time.Since(processStart)/time.Microsecond // WRONG msg := fmt.Sprintf( daemon.SdNotifyReload+"\nMONOTONIC_USEC=%d", ts, ) _, _ = daemon.SdNotify(false, msg) } Help users fall into the pit of success by providing a helper function SdNotifyMonotonicUsec() which returns a MONOTONIC_USEC string which encodes the system CLOCK_MONOTONIC timestamp in decimal microseconds, as systemd expects. Signed-off-by: Cory Snider <csnider@mirantis.com>
- Loading branch information
Showing
4 changed files
with
97 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// Copyright 2024 CoreOS, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package daemon | ||
|
||
import ( | ||
"strconv" | ||
"strings" | ||
"testing" | ||
"time" | ||
|
||
"golang.org/x/sys/unix" | ||
) | ||
|
||
// TestUsec checks that SdNotifyMonotonicUsec is probably not returning complete garbage. | ||
func TestUsec(t *testing.T) { | ||
var resolution unix.Timespec | ||
if err := unix.ClockGetres(unix.CLOCK_MONOTONIC, &resolution); err != nil { | ||
if err == unix.EINVAL { | ||
t.Log("CLOCK_MONOTONIC is not supported on this system") | ||
if got := SdNotifyMonotonicUsec(); got != "" { | ||
t.Errorf("SdNotifyMonotonicUsec() = %q; want empty string", got) | ||
} | ||
return | ||
} | ||
t.Fatalf("ClockGetres(CLOCK_MONOTONIC) failed: %v", err) | ||
} | ||
|
||
now := func() uint64 { | ||
got := SdNotifyMonotonicUsec() | ||
t.Logf("SdNotifyMonotonicUsec() = %q", got) | ||
if got == "" { | ||
t.Fatal("SdNotifyMonotonicUsec() returned empty string on system which supports CLOCK_MONOTONIC") | ||
} | ||
fields := strings.SplitN(got, "=", 2) | ||
if len(fields) != 2 { | ||
t.Fatal("string is not a well-formed variable assignment") | ||
} | ||
tag, val := fields[0], fields[1] | ||
if tag != "MONOTONIC_USEC" { | ||
t.Errorf("expected tag MONOTONIC_USEC, got %q", tag) | ||
} | ||
ts, err := strconv.ParseUint(val, 10, 64) | ||
if err != nil { | ||
t.Fatalf("value %q is not well-formed: %v", val, err) | ||
} | ||
if ts == 0 { | ||
// CLOCK_MONOTONIC is defined on Linux as the number of seconds | ||
// since boot, per clock_gettime(2). A timestamp of zero is | ||
// almost certainly bogus. | ||
t.Fatal("timestamp is zero") | ||
} | ||
return ts | ||
} | ||
|
||
start := now() | ||
time.Sleep(time.Duration(resolution.Nano()) * 3) | ||
ts := now() | ||
if ts < start { | ||
t.Errorf("timestamp went backwards: %d < %d", ts, start) | ||
} else if ts == start { | ||
t.Errorf("timestamp did not advance: %d == %d", ts, start) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,4 @@ | ||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= | ||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||
golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e h1:AqqkRhkzWTerVplYmF0GrGl2ri2S5+F5xhJfDSc/SJY= | ||
golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |