1
2
3
4 package runc
5
6 import (
7 "encoding/json"
8 "os"
9 "os/exec"
10 "path/filepath"
11 "strconv"
12 "strings"
13 "syscall"
14
15 "github.com/pkg/errors"
16 "github.com/sirupsen/logrus"
17
18 "github.com/Microsoft/hcsshim/internal/guest/runtime"
19 )
20
21
22 func (r *runcRuntime) readPidFile(pidFile string) (pid int, err error) {
23 data, err := os.ReadFile(pidFile)
24 if err != nil {
25 return -1, errors.Wrap(err, "failed reading from pid file")
26 }
27 pid, err = strconv.Atoi(string(data))
28 if err != nil {
29 return -1, errors.Wrapf(err, "failed converting pid text %q to integer form", data)
30 }
31 return pid, nil
32 }
33
34
35 func (r *runcRuntime) cleanupContainer(id string) error {
36 containerDir := r.getContainerDir(id)
37 if err := os.RemoveAll(containerDir); err != nil {
38 return errors.Wrapf(err, "failed removing the container directory for container %s", id)
39 }
40 return nil
41 }
42
43
44 func (r *runcRuntime) cleanupProcess(id string, pid int) error {
45 processDir := r.getProcessDir(id, pid)
46 if err := os.RemoveAll(processDir); err != nil {
47 return errors.Wrapf(err, "failed removing the process directory for process %d in container %s", pid, id)
48 }
49 return nil
50 }
51
52
53 func (r *runcRuntime) getProcessDir(id string, pid int) string {
54 containerDir := r.getContainerDir(id)
55 return filepath.Join(containerDir, strconv.Itoa(pid))
56 }
57
58
59
60 func (*runcRuntime) getContainerDir(id string) string {
61 return filepath.Join(containerFilesDir, id)
62 }
63
64
65 func (r *runcRuntime) makeContainerDir(id string) error {
66 dir := r.getContainerDir(id)
67 if err := os.MkdirAll(dir, os.ModeDir); err != nil {
68 return errors.Wrapf(err, "failed making container directory for container %s", id)
69 }
70 return nil
71 }
72
73
74 func (r *runcRuntime) getLogDir(id string) string {
75 return filepath.Join(r.runcLogBasePath, id)
76 }
77
78
79 func (r *runcRuntime) makeLogDir(id string) error {
80 dir := r.getLogDir(id)
81 if err := os.MkdirAll(dir, os.ModeDir); err != nil {
82 return errors.Wrapf(err, "failed making runc log directory for container %s", id)
83 }
84 return nil
85 }
86
87
88 func (r *runcRuntime) getLogPath(id string) string {
89 return filepath.Join(r.getLogDir(id), "runc.log")
90 }
91
92
93
94
95 func (r *runcRuntime) getGlobalLogPath() string {
96
97 return filepath.Join(r.runcLogBasePath, "global-runc.log")
98 }
99
100
101
102
103
104 func (*runcRuntime) processExists(pid int) bool {
105 _, err := os.Stat(filepath.Join("/proc", strconv.Itoa(pid)))
106 return !os.IsNotExist(err)
107 }
108
109
110
111
112 type standardLogEntry struct {
113 Level logrus.Level `json:"level"`
114 Message string `json:"msg"`
115 Err error `json:"error,omitempty"`
116 }
117
118 func (l *standardLogEntry) asError() (err error) {
119 err = parseRuncError(l.Message)
120 if l.Err != nil {
121 err = errors.Wrapf(err, l.Err.Error())
122 }
123 return
124 }
125
126 func parseRuncError(s string) (err error) {
127
128
129 if strings.HasPrefix(s, "container") && strings.HasSuffix(s, "does not exist") {
130
131 err = runtime.ErrContainerDoesNotExist
132 } else if strings.Contains(s, "container with id exists") ||
133 strings.Contains(s, "container with given ID already exists") {
134 err = runtime.ErrContainerAlreadyExists
135 } else if strings.Contains(s, "invalid id format") ||
136 strings.Contains(s, "invalid container ID format") {
137 err = runtime.ErrInvalidContainerID
138 } else if strings.Contains(s, "container") &&
139 strings.Contains(s, "that is not stopped") {
140 err = runtime.ErrContainerNotStopped
141 } else {
142 err = errors.New(s)
143 }
144 return err
145 }
146
147 func getRuncLogError(logPath string) error {
148 reader, err := os.OpenFile(logPath, syscall.O_RDONLY, 0644)
149 if err != nil {
150 return nil
151 }
152 defer reader.Close()
153
154 var lastErr error
155 dec := json.NewDecoder(reader)
156 for {
157 entry := &standardLogEntry{}
158 if err := dec.Decode(entry); err != nil {
159 break
160 }
161 if entry.Level <= logrus.ErrorLevel {
162 lastErr = entry.asError()
163 }
164 }
165 return lastErr
166 }
167
168 func runcCommandLog(logPath string, args ...string) *exec.Cmd {
169 args = append([]string{"--log", logPath, "--log-format", "json"}, args...)
170 return runcCommand(args...)
171 }
172
173 func runcCommand(args ...string) *exec.Cmd {
174 return exec.Command("runc", args...)
175 }
176
View as plain text