summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2017-01-18 16:49:40 -0500
committerLuke Shumaker <lukeshu@sbcglobal.net>2017-01-18 16:50:06 -0500
commitda323d62044ca98455763300596645dc082bd007 (patch)
treefcf40fde3b8c9303f9270a77e4b402cca23837a0
parent76e70fbe6ec8978c1cf36a966bca31c7417d5c67 (diff)
Change the notify signature (again). BREAKING CHANGE.v0.4.0
I think this should reduce the cognitive load of using the function.
-rw-r--r--sd_daemon/log_test.go8
-rw-r--r--sd_daemon/notify.go98
-rw-r--r--sd_daemon/notify_test.go23
3 files changed, 85 insertions, 44 deletions
diff --git a/sd_daemon/log_test.go b/sd_daemon/log_test.go
index 257ccb9..d9937e2 100644
--- a/sd_daemon/log_test.go
+++ b/sd_daemon/log_test.go
@@ -1,4 +1,4 @@
-// Copyright 2016 Luke Shumaker
+// Copyright 2016-2017 Luke Shumaker
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,11 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package sd_daemon
+package sd_daemon_test
import (
"log/syslog"
"testing"
+
+ "git.lukeshu.com/go/libsystemd/sd_daemon"
)
type cbWriter func(p []byte) (n int, err error)
@@ -27,7 +29,7 @@ func (cb cbWriter) Write(p []byte) (n int, err error) {
func TestLog(t *testing.T) {
var written []byte
- log := NewLogger(cbWriter(func(p []byte) (n int, err error) {
+ log := sd_daemon.NewLogger(cbWriter(func(p []byte) (n int, err error) {
written = p
return len(p), nil
}))
diff --git a/sd_daemon/notify.go b/sd_daemon/notify.go
index f2b9076..fcd8060 100644
--- a/sd_daemon/notify.go
+++ b/sd_daemon/notify.go
@@ -1,6 +1,6 @@
// Copyright 2013-2015 Docker, Inc.
// Copyright 2014 CoreOS, Inc.
-// Copyright 2015-2016 Luke Shumaker
+// Copyright 2015-2017 Luke Shumaker
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -24,39 +24,52 @@ import (
"golang.org/x/sys/unix"
)
-// Notify sends a message from process pid to the service manager
-// about state changes. If pid <= 0, or if the current process does
-// not have priveleges to send messages on behalf of other processes,
-// then the message is simply sent from the current process.
+// Notification is a message to be sent to the service manager about
+// state changes.
+type Notification struct {
+ // PID specifies which process to send a notification about.
+ // If PID <= 0, or if the current process does not have
+ // priveleges to send messages on behalf of other processes,
+ // then the message is simply sent from the current process.
+ PID int
+
+ // State should countain a newline-separated list of variable
+ // assignments. See the documentation for sd_notify(3) for
+ // well-known variable assignments.
+ //
+ // https://www.freedesktop.org/software/systemd/man/sd_notify.html
+ State string
+
+ // Files is a list of file descriptors to send to the service
+ // manager with the message. This is useful for keeping files
+ // open across restarts, as it enables the service manager to
+ // pass those files to the new process when it is restarted
+ // (see ListenFds).
+ //
+ // Note: The service manager will only actually store the file
+ // descriptors if you include "FDSTORE=1" in the state (again,
+ // see sd_notify(3) for well-known variable assignments).
+ Files []*os.File
+}
+
+// Send sends the Notification to the service manager.
//
// If unsetEnv is true, then (regardless of whether the function call
// itself succeeds or not) it will unset the environmental variable
-// NOTIFY_SOCKET, which will cause further calls to this function to
-// fail.
-//
-// The state parameter should countain a newline-separated list of
-// variable assignments. See the documentation for sd_notify(3) for
-// well-known variable assignments.
-// https://www.freedesktop.org/software/systemd/man/sd_notify.html
-//
-// It is possible to include a set of file descriptors with the
-// message. This is useful for keeping files open across restarts, as
-// it enables the service manager to pass those files to the new
-// process when it is restarted (see ListenFds). Note: The service
-// manager will only actually store the file descriptors if you
-// include "FDSTORE=1" in the state (again, see sd_notify(3) for
-// well-known variable assignments).
+// NOTIFY_SOCKET, which will cause further notify operations to fail.
//
// If the service manager is not listening for notifications from this
-// process tree (or this has already been called with unsetEnv=true),
-// then ErrDisabled is returned. If the service manager appears to be
-// listening, but there is an error sending the message, then that
-// error is returned. It is generally recommended that you ignore the
-// return value: if there is an error, this is function no-op; meaning
-// that by calling the function but ignoring the return value, you can
-// easily support both service managers that support these
-// notifications and those that do not.
-func Notify(pid int, unsetEnv bool, state string, files []*os.File) error {
+// process tree (or a Notification has has already been send with
+// unsetEnv=true), then ErrDisabled is returned. If the service
+// manager appears to be listening, but there is an error sending the
+// message, then that error is returned.
+//
+// It is generally recommended that you ignore the return value: if
+// there is an error, then this is function no-op; meaning that by
+// calling the function but ignoring the return value, you can easily
+// support both service managers that support these notifications and
+// those that do not.
+func (msg Notification) Send(unsetEnv bool) error {
if unsetEnv {
defer func() { _ = os.Unsetenv("NOTIFY_SOCKET") }()
}
@@ -78,37 +91,40 @@ func Notify(pid int, unsetEnv bool, state string, files []*os.File) error {
var cmsgs [][]byte
- if len(files) > 0 {
- fds := make([]int, len(files))
- for i := range files {
- fds[i] = int(files[i].Fd())
+ if len(msg.Files) > 0 {
+ fds := make([]int, len(msg.Files))
+ for i := range msg.Files {
+ fds[i] = int(msg.Files[i].Fd())
}
cmsg := unix.UnixRights(fds...)
cmsgs = append(cmsgs, cmsg)
}
- havePid := pid > 0 && pid != os.Getpid()
+ havePid := msg.PID > 0 && msg.PID != os.Getpid()
if havePid {
cmsg := unix.UnixCredentials(&unix.Ucred{
- Pid: int32(pid),
+ Pid: int32(msg.PID),
Uid: uint32(os.Getuid()),
Gid: uint32(os.Getgid()),
})
cmsgs = append(cmsgs, cmsg)
}
- // If the 2nd argument is empty, this is equivalent to .Write([]byte(state))
- _, _, err = conn.WriteMsgUnix([]byte(state), bytes.Join(cmsgs, nil), socketAddr)
+ // If the 2nd argument is empty, this is equivalent to
+ //
+ // conn, _ := net.DialUnix(socketAddr.Net, nil, socketAddr)
+ // conn.Write([]byte(msg.State))
+ _, _, err = conn.WriteMsgUnix([]byte(msg.State), bytes.Join(cmsgs, nil), socketAddr)
if err != nil && havePid {
// Maybe it failed because we don't have privileges to
- // spoof our pid, retry without spoofing the pid.
+ // spoof our pid; retry without spoofing the pid.
//
- // I'm not too happy that does this silently without
- // notifying the user, but that's what
+ // I'm not too happy that we do this silently without
+ // notifying the caller, but that's what
// sd_pid_notify_with_fds does.
cmsgs = cmsgs[:len(cmsgs)-1]
- _, _, err = conn.WriteMsgUnix([]byte(state), bytes.Join(cmsgs, nil), socketAddr)
+ _, _, err = conn.WriteMsgUnix([]byte(msg.State), bytes.Join(cmsgs, nil), socketAddr)
}
return err
diff --git a/sd_daemon/notify_test.go b/sd_daemon/notify_test.go
new file mode 100644
index 0000000..b9910ae
--- /dev/null
+++ b/sd_daemon/notify_test.go
@@ -0,0 +1,23 @@
+// Copyright 2016-2017 Luke Shumaker
+//
+// 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 sd_daemon_test
+
+import (
+ "git.lukeshu.com/go/libsystemd/sd_daemon"
+)
+
+func ExampleNotification() {
+ sd_daemon.Notification{State: "READY=1\nSTATUS=Daemon is running"}.Send(false)
+}