1 package main
2
3 import (
4 "bytes"
5 "net"
6 "os"
7 "path"
8 "path/filepath"
9 "strconv"
10 "time"
11
12 "github.com/opencontainers/runc/libcontainer"
13 "github.com/opencontainers/runtime-spec/specs-go"
14 "github.com/urfave/cli"
15 )
16
17 type notifySocket struct {
18 socket *net.UnixConn
19 host string
20 socketPath string
21 }
22
23 func newNotifySocket(context *cli.Context, notifySocketHost string, id string) *notifySocket {
24 if notifySocketHost == "" {
25 return nil
26 }
27
28 root := filepath.Join(context.GlobalString("root"), id)
29 socketPath := filepath.Join(root, "notify", "notify.sock")
30
31 notifySocket := ¬ifySocket{
32 socket: nil,
33 host: notifySocketHost,
34 socketPath: socketPath,
35 }
36
37 return notifySocket
38 }
39
40 func (s *notifySocket) Close() error {
41 return s.socket.Close()
42 }
43
44
45
46 func (s *notifySocket) setupSpec(spec *specs.Spec) {
47 pathInContainer := filepath.Join("/run/notify", path.Base(s.socketPath))
48 mount := specs.Mount{
49 Destination: path.Dir(pathInContainer),
50 Source: path.Dir(s.socketPath),
51 Options: []string{"bind", "nosuid", "noexec", "nodev", "ro"},
52 }
53 spec.Mounts = append(spec.Mounts, mount)
54 spec.Process.Env = append(spec.Process.Env, "NOTIFY_SOCKET="+pathInContainer)
55 }
56
57 func (s *notifySocket) bindSocket() error {
58 addr := net.UnixAddr{
59 Name: s.socketPath,
60 Net: "unixgram",
61 }
62
63 socket, err := net.ListenUnixgram("unixgram", &addr)
64 if err != nil {
65 return err
66 }
67
68 err = os.Chmod(s.socketPath, 0o777)
69 if err != nil {
70 socket.Close()
71 return err
72 }
73
74 s.socket = socket
75 return nil
76 }
77
78 func (s *notifySocket) setupSocketDirectory() error {
79 return os.Mkdir(path.Dir(s.socketPath), 0o755)
80 }
81
82 func notifySocketStart(context *cli.Context, notifySocketHost, id string) (*notifySocket, error) {
83 notifySocket := newNotifySocket(context, notifySocketHost, id)
84 if notifySocket == nil {
85 return nil, nil
86 }
87
88 if err := notifySocket.bindSocket(); err != nil {
89 return nil, err
90 }
91 return notifySocket, nil
92 }
93
94 func (n *notifySocket) waitForContainer(container libcontainer.Container) error {
95 s, err := container.State()
96 if err != nil {
97 return err
98 }
99 return n.run(s.InitProcessPid)
100 }
101
102 func (n *notifySocket) run(pid1 int) error {
103 if n.socket == nil {
104 return nil
105 }
106 notifySocketHostAddr := net.UnixAddr{Name: n.host, Net: "unixgram"}
107 client, err := net.DialUnix("unixgram", nil, ¬ifySocketHostAddr)
108 if err != nil {
109 return err
110 }
111
112 ticker := time.NewTicker(time.Millisecond * 100)
113 defer ticker.Stop()
114
115 fileChan := make(chan []byte)
116 go func() {
117 for {
118 buf := make([]byte, 4096)
119 r, err := n.socket.Read(buf)
120 if err != nil {
121 return
122 }
123 got := buf[0:r]
124
125
126 for _, line := range bytes.Split(got, []byte{'\n'}) {
127 if bytes.HasPrefix(got, []byte("READY=")) {
128 fileChan <- line
129 return
130 }
131 }
132
133 }
134 }()
135
136 for {
137 select {
138 case <-ticker.C:
139 _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid1)))
140 if err != nil {
141 return nil
142 }
143 case b := <-fileChan:
144 var out bytes.Buffer
145 _, err = out.Write(b)
146 if err != nil {
147 return err
148 }
149
150 _, err = out.Write([]byte{'\n'})
151 if err != nil {
152 return err
153 }
154
155 _, err = client.Write(out.Bytes())
156 if err != nil {
157 return err
158 }
159
160
161 newPid := "MAINPID=" + strconv.Itoa(pid1)
162 _, err := client.Write([]byte(newPid + "\n"))
163 if err != nil {
164 return err
165 }
166 return nil
167 }
168 }
169 }
170
View as plain text