Skip to content

Commit de8d0d3

Browse files
author
Kathryn Baldauf
committed
Update runc kill wrapper to take a string for signal
Signed-off-by: Kathryn Baldauf <[email protected]>
1 parent d1e3ca2 commit de8d0d3

File tree

2 files changed

+94
-5
lines changed

2 files changed

+94
-5
lines changed

runc.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@ func (r *Runc) Delete(context context.Context, id string, opts *DeleteOpts) erro
327327
type KillOpts struct {
328328
All bool
329329
ExtraArgs []string
330+
RawSignal string
330331
}
331332

332333
func (o *KillOpts) args() (out []string) {
@@ -344,10 +345,14 @@ func (r *Runc) Kill(context context.Context, id string, sig int, opts *KillOpts)
344345
args := []string{
345346
"kill",
346347
}
348+
killSignal := strconv.Itoa(sig)
347349
if opts != nil {
348350
args = append(args, opts.args()...)
351+
if opts.RawSignal != "" {
352+
killSignal = opts.RawSignal
353+
}
349354
}
350-
return r.runOrError(r.command(context, append(args, id, strconv.Itoa(sig))...))
355+
return r.runOrError(r.command(context, append(args, id, killSignal)...))
351356
}
352357

353358
// Stats return the stats for a container like cpu, memory, and io

runc_test.go

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"errors"
2222
"io/ioutil"
2323
"os"
24+
"strings"
2425
"sync"
2526
"syscall"
2627
"testing"
@@ -287,9 +288,7 @@ func interrupt(ctx context.Context, t *testing.T, started <-chan int) {
287288
}
288289
}
289290

290-
// dummySleepRunc creates s simple script that just runs `sleep 10` to replace
291-
// runc for testing process that are longer running.
292-
func dummySleepRunc() (_ string, err error) {
291+
func createScript(content string) (_ string, err error) {
293292
fh, err := ioutil.TempFile("", "*.sh")
294293
if err != nil {
295294
return "", err
@@ -299,7 +298,7 @@ func dummySleepRunc() (_ string, err error) {
299298
os.Remove(fh.Name())
300299
}
301300
}()
302-
_, err = fh.Write([]byte("#!/bin/sh\nexec /bin/sleep 10"))
301+
_, err = fh.Write([]byte(content))
303302
if err != nil {
304303
return "", err
305304
}
@@ -314,6 +313,22 @@ func dummySleepRunc() (_ string, err error) {
314313
return fh.Name(), nil
315314
}
316315

316+
// dummySleepRunc creates a simple script that just runs `sleep 10` to replace
317+
// runc for testing process that are longer running.
318+
func dummySleepRunc() (_ string, err error) {
319+
return createScript("#!/bin/sh\nexec /bin/sleep 10")
320+
}
321+
322+
// debugCommand creates a simple script that echos the arguments passed to
323+
// runc, and returns them as part of the error message.
324+
func debugCommand() (string, error) {
325+
return createScript(`#!/bin/sh
326+
echo "$@"
327+
# force non-zero exit code, so that the error message contains the output
328+
exit 1
329+
`)
330+
}
331+
317332
func TestCreateArgs(t *testing.T) {
318333
o := &CreateOpts{}
319334
args, err := o.args()
@@ -336,3 +351,72 @@ func TestCreateArgs(t *testing.T) {
336351
}
337352

338353
}
354+
355+
func TestRuncKill(t *testing.T) {
356+
ctx, timeout := context.WithTimeout(context.Background(), 10*time.Second)
357+
defer timeout()
358+
359+
dummyCmd, err := debugCommand()
360+
if err != nil {
361+
t.Fatalf("Failed to create dummy debug command: %v", err)
362+
}
363+
defer os.Remove(dummyCmd)
364+
365+
debugRunc := &Runc{Command: dummyCmd}
366+
367+
type config struct {
368+
name string
369+
rawSignal string
370+
numericalSignal int
371+
expectedSignal string
372+
}
373+
tests := []config{
374+
{
375+
name: "Kill sends raw signal",
376+
rawSignal: "SIGTERM",
377+
expectedSignal: "SIGTERM",
378+
},
379+
{
380+
name: "Kill sends raw signal number",
381+
rawSignal: "15",
382+
expectedSignal: "15",
383+
},
384+
{
385+
name: "Kill prefers raw signal over numerical signal",
386+
rawSignal: "SIGTERM",
387+
numericalSignal: 9,
388+
expectedSignal: "SIGTERM",
389+
},
390+
{
391+
name: "Kill prefers raw signal number over numerical signal",
392+
rawSignal: "15",
393+
numericalSignal: 9,
394+
expectedSignal: "15",
395+
},
396+
{
397+
name: "Kill sends numerical signal when no raw signal specified",
398+
numericalSignal: 9,
399+
expectedSignal: "9",
400+
},
401+
}
402+
for _, test := range tests {
403+
t.Run(test.name, func(_ *testing.T) {
404+
opts := &KillOpts{
405+
RawSignal: test.rawSignal,
406+
}
407+
err = debugRunc.Kill(ctx, "fake_id", test.numericalSignal, opts)
408+
if err == nil {
409+
t.Fatal("expected dummy debug command to return error, instead got nil")
410+
}
411+
errorMessage := err.Error()
412+
words := strings.Fields(errorMessage)
413+
if len(words) < 3 {
414+
t.Fatalf("expected dummy debug command to error with the kill command sent, instead got %s", errorMessage)
415+
}
416+
actualSignal := words[len(words)-1]
417+
if actualSignal != test.expectedSignal {
418+
t.Fatalf("expected kill command to send signal %v, instead got %v", test.expectedSignal, actualSignal)
419+
}
420+
})
421+
}
422+
}

0 commit comments

Comments
 (0)