@@ -7,11 +7,13 @@ import (
7
7
"fmt"
8
8
"net"
9
9
"os"
10
+ "path"
10
11
"path/filepath"
12
+ "strconv"
13
+ "time"
11
14
15
+ "github.com/opencontainers/runc/libcontainer"
12
16
"github.com/opencontainers/runtime-spec/specs-go"
13
-
14
- "github.com/sirupsen/logrus"
15
17
"github.com/urfave/cli"
16
18
)
17
19
@@ -27,12 +29,12 @@ func newNotifySocket(context *cli.Context, notifySocketHost string, id string) *
27
29
}
28
30
29
31
root := filepath .Join (context .GlobalString ("root" ), id )
30
- path := filepath .Join (root , "notify.sock" )
32
+ socketPath := filepath .Join (root , "notify" , "notify.sock" )
31
33
32
34
notifySocket := & notifySocket {
33
35
socket : nil ,
34
36
host : notifySocketHost ,
35
- socketPath : path ,
37
+ socketPath : socketPath ,
36
38
}
37
39
38
40
return notifySocket
@@ -44,13 +46,19 @@ func (s *notifySocket) Close() error {
44
46
45
47
// If systemd is supporting sd_notify protocol, this function will add support
46
48
// for sd_notify protocol from within the container.
47
- func (s * notifySocket ) setupSpec (context * cli.Context , spec * specs.Spec ) {
48
- mount := specs.Mount {Destination : s .host , Source : s .socketPath , Options : []string {"bind" }}
49
+ func (s * notifySocket ) setupSpec (context * cli.Context , spec * specs.Spec ) error {
50
+ pathInContainer := filepath .Join ("/run/notify" , path .Base (s .socketPath ))
51
+ mount := specs.Mount {
52
+ Destination : path .Dir (pathInContainer ),
53
+ Source : path .Dir (s .socketPath ),
54
+ Options : []string {"bind" , "nosuid" , "noexec" , "nodev" , "ro" },
55
+ }
49
56
spec .Mounts = append (spec .Mounts , mount )
50
- spec .Process .Env = append (spec .Process .Env , fmt .Sprintf ("NOTIFY_SOCKET=%s" , s .host ))
57
+ spec .Process .Env = append (spec .Process .Env , fmt .Sprintf ("NOTIFY_SOCKET=%s" , pathInContainer ))
58
+ return nil
51
59
}
52
60
53
- func (s * notifySocket ) setupSocket () error {
61
+ func (s * notifySocket ) bindSocket () error {
54
62
addr := net.UnixAddr {
55
63
Name : s .socketPath ,
56
64
Net : "unixgram" ,
@@ -71,46 +79,92 @@ func (s *notifySocket) setupSocket() error {
71
79
return nil
72
80
}
73
81
74
- // pid1 must be set only with -d, as it is used to set the new process as the main process
75
- // for the service in systemd
76
- func (s * notifySocket ) run (pid1 int ) {
77
- buf := make ([]byte , 512 )
78
- notifySocketHostAddr := net.UnixAddr {Name : s .host , Net : "unixgram" }
82
+ func (s * notifySocket ) setupSocketDirectory () error {
83
+ return os .Mkdir (path .Dir (s .socketPath ), 0755 )
84
+ }
85
+
86
+ func notifySocketStart (context * cli.Context , notifySocketHost , id string ) (* notifySocket , error ) {
87
+ notifySocket := newNotifySocket (context , notifySocketHost , id )
88
+ if notifySocket == nil {
89
+ return nil , nil
90
+ }
91
+
92
+ if err := notifySocket .bindSocket (); err != nil {
93
+ return nil , err
94
+ }
95
+ return notifySocket , nil
96
+ }
97
+
98
+ func (n * notifySocket ) waitForContainer (container libcontainer.Container ) error {
99
+ s , err := container .State ()
100
+ if err != nil {
101
+ return err
102
+ }
103
+ return n .run (s .InitProcessPid )
104
+ }
105
+
106
+ func (n * notifySocket ) run (pid1 int ) error {
107
+ if n .socket == nil {
108
+ return nil
109
+ }
110
+ notifySocketHostAddr := net.UnixAddr {Name : n .host , Net : "unixgram" }
79
111
client , err := net .DialUnix ("unixgram" , nil , & notifySocketHostAddr )
80
112
if err != nil {
81
- logrus .Error (err )
82
- return
113
+ return err
83
114
}
84
- for {
85
- r , err := s .socket .Read (buf )
86
- if err != nil {
87
- break
88
- }
89
- var out bytes.Buffer
90
- for _ , line := range bytes .Split (buf [0 :r ], []byte {'\n' }) {
91
- if bytes .HasPrefix (line , []byte ("READY=" )) {
92
- _ , err = out .Write (line )
93
- if err != nil {
94
- return
95
- }
96
115
97
- _ , err = out .Write ([]byte {'\n' })
98
- if err != nil {
99
- return
100
- }
116
+ ticker := time .NewTicker (time .Millisecond * 100 )
117
+ defer ticker .Stop ()
101
118
102
- _ , err = client .Write (out .Bytes ())
103
- if err != nil {
119
+ fileChan := make (chan []byte )
120
+ go func () {
121
+ for {
122
+ buf := make ([]byte , 4096 )
123
+ r , err := n .socket .Read (buf )
124
+ if err != nil {
125
+ return
126
+ }
127
+ got := buf [0 :r ]
128
+ // systemd-ready sends a single datagram with the state string as payload,
129
+ // so we don't need to worry about partial messages.
130
+ for _ , line := range bytes .Split (got , []byte {'\n' }) {
131
+ if bytes .HasPrefix (got , []byte ("READY=" )) {
132
+ fileChan <- line
104
133
return
105
134
}
135
+ }
106
136
107
- // now we can inform systemd to use pid1 as the pid to monitor
108
- if pid1 > 0 {
109
- newPid := fmt .Sprintf ("MAINPID=%d\n " , pid1 )
110
- client .Write ([]byte (newPid ))
111
- }
112
- return
137
+ }
138
+ }()
139
+
140
+ for {
141
+ select {
142
+ case <- ticker .C :
143
+ _ , err := os .Stat (filepath .Join ("/proc" , strconv .Itoa (pid1 )))
144
+ if err != nil {
145
+ return nil
113
146
}
147
+ case b := <- fileChan :
148
+ var out bytes.Buffer
149
+ _ , err = out .Write (b )
150
+ if err != nil {
151
+ return err
152
+ }
153
+
154
+ _ , err = out .Write ([]byte {'\n' })
155
+ if err != nil {
156
+ return err
157
+ }
158
+
159
+ _ , err = client .Write (out .Bytes ())
160
+ if err != nil {
161
+ return err
162
+ }
163
+
164
+ // now we can inform systemd to use pid1 as the pid to monitor
165
+ newPid := fmt .Sprintf ("MAINPID=%d\n " , pid1 )
166
+ client .Write ([]byte (newPid ))
167
+ return nil
114
168
}
115
169
}
116
170
}
0 commit comments