1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package chaosdaemon
17
18 import (
19 "context"
20 "fmt"
21 "io/ioutil"
22 "os"
23 "strings"
24
25 "github.com/golang/protobuf/ptypes/empty"
26
27 "github.com/chaos-mesh/chaos-mesh/pkg/bpm"
28 pb "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/pb"
29 )
30
31 const (
32 bmInstallCommand = "bminstall.sh -b -Dorg.jboss.byteman.transform.all -Dorg.jboss.byteman.verbose -p %d %d"
33 bmSubmitCommand = "bmsubmit.sh -p %d -%s %s"
34 )
35
36 func (s *DaemonServer) InstallJVMRules(ctx context.Context,
37 req *pb.InstallJVMRulesRequest) (*empty.Empty, error) {
38 log := s.getLoggerFromContext(ctx)
39 log.Info("InstallJVMRules", "request", req)
40 pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId)
41 if err != nil {
42 log.Error(err, "GetPidFromContainerID")
43 return nil, err
44 }
45
46 bytemanHome := os.Getenv("BYTEMAN_HOME")
47 if len(bytemanHome) == 0 {
48 return nil, fmt.Errorf("environment variable BYTEMAN_HOME not set")
49 }
50
51
52 if req.EnterNS {
53 processBuilder := bpm.DefaultProcessBuilder("sh", "-c", fmt.Sprintf("mkdir -p %s/lib/", bytemanHome)).SetContext(ctx).SetNS(pid, bpm.MountNS)
54 output, err := processBuilder.Build(ctx).CombinedOutput()
55 if err != nil {
56 return nil, err
57 }
58 if len(output) > 0 {
59 log.Info("mkdir", "output", string(output))
60 }
61
62 agentFile, err := os.Open(fmt.Sprintf("%s/lib/byteman.jar", bytemanHome))
63 if err != nil {
64 return nil, err
65 }
66 processBuilder = bpm.DefaultProcessBuilder("sh", "-c", "cat > /usr/local/byteman/lib/byteman.jar").SetContext(ctx)
67 processBuilder = processBuilder.SetNS(pid, bpm.MountNS).SetStdin(agentFile)
68 output, err = processBuilder.Build(ctx).CombinedOutput()
69 if err != nil {
70 return nil, err
71 }
72 if len(output) > 0 {
73 log.Info("copy agent.jar", "output", string(output))
74 }
75 }
76
77 bmInstallCmd := fmt.Sprintf(bmInstallCommand, req.Port, pid)
78 processBuilder := bpm.DefaultProcessBuilder("sh", "-c", bmInstallCmd).SetContext(ctx)
79 if req.EnterNS {
80 processBuilder = processBuilder.EnableLocalMnt()
81 }
82
83 cmd := processBuilder.Build(ctx)
84 output, err := cmd.CombinedOutput()
85 if err != nil {
86
87 errMsg1 := "Agent JAR loaded but agent failed to initialize"
88
89
90
91
92 errMsg2 := "Provider sun.tools.attach.LinuxAttachProvider not found"
93 errMsg3 := "install java.io.IOException: Non-numeric value found"
94
95
96
97 errMsg4 := "install com.sun.tools.attach.AgentLoadException"
98 if !strings.Contains(string(output), errMsg1) && !strings.Contains(string(output), errMsg2) &&
99 !strings.Contains(string(output), errMsg3) && !strings.Contains(string(output), errMsg4) {
100 log.Error(err, string(output))
101 return nil, err
102 }
103 log.Info("exec comamnd", "cmd", cmd.String(), "output", string(output), "error", err.Error())
104 }
105
106
107 filename, err := writeDataIntoFile(req.Rule, "rule.btm")
108 if err != nil {
109 return nil, err
110 }
111
112 bmSubmitCmd := fmt.Sprintf(bmSubmitCommand, req.Port, "l", filename)
113 processBuilder = bpm.DefaultProcessBuilder("sh", "-c", bmSubmitCmd).SetContext(ctx)
114 if req.EnterNS {
115 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
116 }
117 output, err = processBuilder.Build(ctx).CombinedOutput()
118 if err != nil {
119 log.Error(err, string(output))
120 return nil, err
121 }
122 if len(output) > 0 {
123 log.Info("submit rules", "output", string(output))
124 }
125
126 return &empty.Empty{}, nil
127 }
128
129 func (s *DaemonServer) UninstallJVMRules(ctx context.Context,
130 req *pb.UninstallJVMRulesRequest) (*empty.Empty, error) {
131 log := s.getLoggerFromContext(ctx)
132 log.Info("InstallJVMRules", "request", req)
133 pid, err := s.crClient.GetPidFromContainerID(ctx, req.ContainerId)
134 if err != nil {
135 log.Error(err, "GetPidFromContainerID")
136 return nil, err
137 }
138
139 filename, err := writeDataIntoFile(req.Rule, "rule.btm")
140 if err != nil {
141 return nil, err
142 }
143 log.Info("create btm file", "file", filename)
144
145 bmSubmitCmd := fmt.Sprintf(bmSubmitCommand, req.Port, "u", filename)
146 processBuilder := bpm.DefaultProcessBuilder("sh", "-c", bmSubmitCmd).SetContext(ctx)
147 if req.EnterNS {
148 processBuilder = processBuilder.SetNS(pid, bpm.NetNS)
149 }
150 output, err := processBuilder.Build(ctx).CombinedOutput()
151 if err != nil {
152 log.Error(err, string(output))
153 if strings.Contains(string(output), "No rule scripts to remove") {
154 return &empty.Empty{}, nil
155 }
156 return nil, err
157 }
158
159 if len(output) > 0 {
160 log.Info(string(output))
161 }
162
163 return &empty.Empty{}, nil
164 }
165
166 func writeDataIntoFile(data string, filename string) (string, error) {
167 tmpfile, err := ioutil.TempFile("", filename)
168 if err != nil {
169 return "", err
170 }
171
172 if _, err := tmpfile.WriteString(data); err != nil {
173 return "", err
174 }
175
176 if err := tmpfile.Close(); err != nil {
177 return "", err
178 }
179
180 return tmpfile.Name(), err
181 }
182