Skip to content

Commit 5b453a9

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 5b453a9

File tree

2 files changed

+95
-5
lines changed

2 files changed

+95
-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: 89 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,23 @@ 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+
328+
# force non-zero exit code, so that the error message contains the output
329+
exit 1
330+
`)
331+
}
332+
317333
func TestCreateArgs(t *testing.T) {
318334
o := &CreateOpts{}
319335
args, err := o.args()
@@ -336,3 +352,72 @@ func TestCreateArgs(t *testing.T) {
336352
}
337353

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

0 commit comments

Comments
 (0)