Skip to content

Commit

Permalink
Add stress-ng to target pid namespace (chaos-mesh#685)
Browse files Browse the repository at this point in the history
* add -F and corresponding arguments to nsenter

Signed-off-by: yangkeao <[email protected]>

* use infinite reader as stdin

Signed-off-by: Yang Keao <[email protected]>

* normal program

Signed-off-by: Yang Keao <[email protected]>

* don't use toolkit in busybox!

Signed-off-by: Yang Keao <[email protected]>

* remove no-fork for nsenter

Signed-off-by: Yang Keao <[email protected]>

* add new pgid

Signed-off-by: Yang Keao <[email protected]>

* dev on minikube

Signed-off-by: Yang Keao <[email protected]>

* add logs and kill children

Signed-off-by: Yang Keao <[email protected]>

* check back value.yaml

Signed-off-by: Yang Keao <[email protected]>

* remove redundant logs

Signed-off-by: Yang Keao <[email protected]>

Co-authored-by: AngleNet <[email protected]>
Co-authored-by: CWen <[email protected]>
  • Loading branch information
3 people authored Jul 13, 2020
1 parent 348943d commit 4d64ca8
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 13 deletions.
2 changes: 1 addition & 1 deletion images/chaos-daemon/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ FROM alpine:3.10
ARG HTTPS_PROXY
ARG HTTP_PROXY

RUN apk add --no-cache tzdata iptables ipset stress-ng iproute2
RUN apk add --no-cache tzdata iptables ipset stress-ng iproute2 util-linux

COPY --from=pingcap/binary /src/bin/chaos-daemon /usr/local/bin/chaos-daemon
2 changes: 1 addition & 1 deletion pkg/chaosdaemon/ipset_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (s *daemonServer) FlushIpSet(ctx context.Context, req *pb.IpSetRequest) (*e
return nil, err
}

nsPath := GenNetnsPath(pid)
nsPath := GetNsPath(pid, netNS)

// TODO: lock every ipset when working on it

Expand Down
2 changes: 1 addition & 1 deletion pkg/chaosdaemon/iptables_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (s *daemonServer) FlushIptables(ctx context.Context, req *pb.IpTablesReques
return nil, err
}

nsPath := GenNetnsPath(pid)
nsPath := GetNsPath(pid, netNS)
rule := req.Rule

format := ""
Expand Down
4 changes: 2 additions & 2 deletions pkg/chaosdaemon/netlink_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ type toQdiscFunc func(*netlink.Handle, netlink.Link) netlink.Qdisc
func applyQdisc(pid uint32, toQdisc toQdiscFunc) error {
log.Info("Apply qdisc on PID", "pid", pid)

ns, err := netns.GetFromPath(GenNetnsPath(pid))
ns, err := netns.GetFromPath(GetNsPath(pid, netNS))
if err != nil {
log.Error(err, "failed to find network namespace", "pid", pid)
return err
Expand Down Expand Up @@ -60,7 +60,7 @@ func applyQdisc(pid uint32, toQdisc toQdiscFunc) error {
func deleteQdisc(pid uint32, toQdisc toQdiscFunc) error {
log.Info("Delete qdisc on PID", "pid", pid)

ns, err := netns.GetFromPath(GenNetnsPath(pid))
ns, err := netns.GetFromPath(GetNsPath(pid, netNS))
if err != nil {
log.Error(err, "failed to find network namespace", "pid", pid)
return err
Expand Down
18 changes: 16 additions & 2 deletions pkg/chaosdaemon/stress_server_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,14 @@ func (s *daemonServer) ExecStressors(ctx context.Context,
if err != nil {
return nil, err
}
cmd := exec.Command("stress-ng", strings.Fields(req.Stressors)...)

cmd := withPidNS(context.Background(), GetNsPath(pid, pidNS), "stress-ng", strings.Fields(req.Stressors)...)

if err := cmd.Start(); err != nil {
return nil, err
}
log.Info("Start process successfully")

procState, err := process.NewProcess(int32(cmd.Process.Pid))
if err != nil {
return nil, err
Expand Down Expand Up @@ -108,15 +112,25 @@ func (s *daemonServer) CancelStressors(ctx context.Context,
return nil, err
}
log.Info("Canceling stressors", "request", req)

ins, err := process.NewProcess(int32(pid))
if err != nil {
return &empty.Empty{}, nil
}
if ct, err := ins.CreateTime(); err == nil && ct == req.StartTime {
if err := ins.Kill(); err != nil {
children, err := ins.Children()
if err != nil {
return nil, err
}
for _, child := range children {
log.Info("killing children for nsenter", "pid", child.Pid)
if err := child.Kill(); err != nil {
return nil, err
}
}
}

log.Info("Successfully canceled stressors")
return &empty.Empty{}, nil
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/chaosdaemon/tc_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func applyTc(ctx context.Context, pid uint32, args ...string) error {
}
}

nsPath := GenNetnsPath(pid)
nsPath := GetNsPath(pid, netNS)

cmd := withNetNS(ctx, nsPath, "tc", args...)
log.Info("tc command", "command", cmd.String(), "args", args)
Expand Down
66 changes: 61 additions & 5 deletions pkg/chaosdaemon/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"os"
"os/exec"
"strconv"
"strings"
"sync"
"syscall"

Expand Down Expand Up @@ -184,9 +185,29 @@ func CreateContainerRuntimeInfoClient(containerRuntime string) (ContainerRuntime
return cli, nil
}

// GetNetnsPath returns network namespace path
func GenNetnsPath(pid uint32) string {
return fmt.Sprintf("%s/%d/ns/net", defaultProcPrefix, pid)
type nsType string

const (
mountNS nsType = "mnt"
utsNS nsType = "uts"
ipcNS nsType = "ipc"
netNS nsType = "net"
pidNS nsType = "pid"
userNS nsType = "user"
)

var nsArgMap = map[nsType]string{
mountNS: "m",
utsNS: "u",
ipcNS: "i",
netNS: "n",
pidNS: "p",
userNS: "U",
}

// GetNsPath returns corresponding namespace path
func GetNsPath(pid uint32, typ nsType) string {
return fmt.Sprintf("%s/%d/ns/%s", defaultProcPrefix, pid, string(typ))
}

func withNetNS(ctx context.Context, nsPath string, cmd string, args ...string) *exec.Cmd {
Expand All @@ -196,8 +217,43 @@ func withNetNS(ctx context.Context, nsPath string, cmd string, args ...string) *
return f(ctx, nsPath, cmd, args...)
}

// BusyBox's nsenter is very confusing. This usage is found by several attempts
args = append([]string{"-n" + nsPath, "--", cmd}, args...)
return withNS(ctx, []nsOption{{
Typ: netNS,
Path: nsPath,
}}, cmd, args...)
}

func withPidNS(ctx context.Context, nsPath string, cmd string, args ...string) *exec.Cmd {
// Mock point to return mock Cmd in unit test
if c := mock.On("MockWithPidNs"); c != nil {
f := c.(func(context.Context, string, string, ...string) *exec.Cmd)
return f(ctx, nsPath, cmd, args...)
}

return withNS(ctx, []nsOption{{
Typ: pidNS,
Path: nsPath,
}}, cmd, args...)
}

type nsOption struct {
Typ nsType
Path string
}

func withNS(ctx context.Context, options []nsOption, cmd string, args ...string) *exec.Cmd {
// Mock point to return mock Cmd in unit test
if c := mock.On("MockWithNs"); c != nil {
f := c.(func(context.Context, []nsOption, string, ...string) *exec.Cmd)
return f(ctx, options, cmd, args...)
}

args = append([]string{"--", cmd}, args...)
for _, option := range options {
args = append([]string{"-" + nsArgMap[option.Typ] + option.Path}, args...)
}

log.Info("running command", "command", "nsenter "+strings.Join(args, " "))

return exec.CommandContext(ctx, "nsenter", args...)
}
Expand Down

0 comments on commit 4d64ca8

Please sign in to comment.