summaryrefslogtreecommitdiff
path: root/pkg/systemd
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/systemd')
-rw-r--r--pkg/systemd/notifyproxy/notifyproxy.go65
-rw-r--r--pkg/systemd/notifyproxy/notifyproxy_test.go2
2 files changed, 61 insertions, 6 deletions
diff --git a/pkg/systemd/notifyproxy/notifyproxy.go b/pkg/systemd/notifyproxy/notifyproxy.go
index 9e6eb4cf0..1bfab9ca0 100644
--- a/pkg/systemd/notifyproxy/notifyproxy.go
+++ b/pkg/systemd/notifyproxy/notifyproxy.go
@@ -1,12 +1,17 @@
package notifyproxy
import (
+ "errors"
+ "fmt"
+ "io"
"io/ioutil"
"net"
"os"
"strings"
"syscall"
+ "time"
+ "github.com/containers/podman/v4/libpod/define"
"github.com/coreos/go-systemd/v22/daemon"
"github.com/sirupsen/logrus"
)
@@ -39,6 +44,7 @@ func SendMessage(socketPath string, message string) error {
type NotifyProxy struct {
connection *net.UnixConn
socketPath string
+ container Container // optional
}
// New creates a NotifyProxy. The specified temp directory can be left empty.
@@ -77,9 +83,26 @@ func (p *NotifyProxy) close() error {
return p.connection.Close()
}
+// AddContainer associates a container with the proxy.
+func (p *NotifyProxy) AddContainer(container Container) {
+ p.container = container
+}
+
+// ErrNoReadyMessage is returned when we are waiting for the READY message of a
+// container that is not in the running state anymore.
+var ErrNoReadyMessage = errors.New("container stopped running before READY message was received")
+
+// Container avoids a circular dependency among this package and libpod.
+type Container interface {
+ State() (define.ContainerStatus, error)
+ ID() string
+}
+
// WaitAndClose waits until receiving the `READY` notify message and close the
// listener. Note that the this function must only be executed inside a systemd
// service which will kill the process after a given timeout.
+// If the (optional) container stopped running before the `READY` is received,
+// the waiting gets canceled and ErrNoReadyMessage is returned.
func (p *NotifyProxy) WaitAndClose() error {
defer func() {
if err := p.close(); err != nil {
@@ -87,16 +110,48 @@ func (p *NotifyProxy) WaitAndClose() error {
}
}()
+ const bufferSize = 1024
+ sBuilder := strings.Builder{}
for {
- buf := make([]byte, 1024)
- num, err := p.connection.Read(buf)
- if err != nil {
+ // Set a read deadline of one second such that we achieve a
+ // non-blocking read and can check if the container has already
+ // stopped running; in that case no READY message will be send
+ // and we're done.
+ if err := p.connection.SetReadDeadline(time.Now().Add(time.Second)); err != nil {
return err
}
- for _, s := range strings.Split(string(buf[:num]), "\n") {
- if s == daemon.SdNotifyReady {
+
+ for {
+ buffer := make([]byte, bufferSize)
+ num, err := p.connection.Read(buffer)
+ if err != nil {
+ if !errors.Is(err, os.ErrDeadlineExceeded) && !errors.Is(err, io.EOF) {
+ return err
+ }
+ }
+ sBuilder.Write(buffer[:num])
+ if num != bufferSize || buffer[num-1] == '\n' {
+ break
+ }
+ }
+
+ for _, line := range strings.Split(sBuilder.String(), "\n") {
+ if line == daemon.SdNotifyReady {
return nil
}
}
+ sBuilder.Reset()
+
+ if p.container == nil {
+ continue
+ }
+
+ state, err := p.container.State()
+ if err != nil {
+ return err
+ }
+ if state != define.ContainerStateRunning {
+ return fmt.Errorf("%w: %s", ErrNoReadyMessage, p.container.ID())
+ }
}
}
diff --git a/pkg/systemd/notifyproxy/notifyproxy_test.go b/pkg/systemd/notifyproxy/notifyproxy_test.go
index ce63fc9cd..066046cb8 100644
--- a/pkg/systemd/notifyproxy/notifyproxy_test.go
+++ b/pkg/systemd/notifyproxy/notifyproxy_test.go
@@ -41,7 +41,7 @@ func TestWaitAndClose(t *testing.T) {
default:
}
- sendMessage(t, proxy, daemon.SdNotifyReady+"\nsomething else")
+ sendMessage(t, proxy, daemon.SdNotifyReady+"\nsomething else\n")
done := func() bool {
for i := 0; i < 10; i++ {
select {