1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package main
17
18 import (
19 "bytes"
20 "encoding/json"
21 "flag"
22 "fmt"
23 "io"
24 "io/ioutil"
25 "net"
26 "net/http"
27 "os"
28 "path/filepath"
29 "time"
30
31 "github.com/containerd/cgroups"
32 )
33
34 func main() {
35 port := flag.Int("port", 8080, "listen port")
36 dataDir := flag.String("data-dir", "/var/run/data", "data dir is the dir to write temp file, only used in io test")
37
38 flag.Parse()
39
40 s := newServer(*dataDir)
41 err := s.setupUDPServer()
42 if err != nil {
43 fmt.Println("failed to serve udp server", err)
44 os.Exit(1)
45 }
46
47 addr := fmt.Sprintf("0.0.0.0:%d", *port)
48 if err := http.ListenAndServe(addr, s.mux); err != nil {
49 fmt.Println("failed to serve http server", err)
50 os.Exit(1)
51 }
52 }
53
54 type server struct {
55 mux *http.ServeMux
56 dataDir string
57
58
59 recvBuf []byte
60 }
61
62 func newServer(dataDir string) *server {
63 s := &server{
64 mux: http.NewServeMux(),
65 dataDir: dataDir,
66 recvBuf: make([]byte, 5),
67 }
68 s.mux.HandleFunc("/ping", pong)
69 s.mux.HandleFunc("/time", s.timer)
70 s.mux.HandleFunc("/io", s.ioTest)
71 s.mux.HandleFunc("/mistake", s.mistakeTest)
72 s.mux.HandleFunc("/network/send", s.networkSendTest)
73 s.mux.HandleFunc("/network/recv", s.networkRecvTest)
74 s.mux.HandleFunc("/network/ping", s.networkPingTest)
75 s.mux.HandleFunc("/dns", s.dnsTest)
76 s.mux.HandleFunc("/stress", s.stressCondition)
77 s.mux.HandleFunc("/http", s.httpEcho)
78 return s
79 }
80
81 func pong(w http.ResponseWriter, _ *http.Request) {
82 w.Write([]byte("pong"))
83 }
84
85 func (s *server) setupUDPServer() error {
86 pc, err := net.ListenPacket("udp", "0.0.0.0:1070")
87 if err != nil {
88 return err
89 }
90
91 go func() {
92 for {
93 _, _, err := pc.ReadFrom(s.recvBuf)
94 fmt.Println("receive buf " + string(s.recvBuf))
95 if err != nil {
96 return
97 }
98 }
99 }()
100
101 return nil
102 }
103
104
105 func (s *server) timer(w http.ResponseWriter, _ *http.Request) {
106 w.Write([]byte(time.Now().Format(time.RFC3339Nano)))
107 }
108
109
110 func (s *server) mistakeTest(w http.ResponseWriter, _ *http.Request) {
111 path := filepath.Join(s.dataDir, "e2e-test")
112 origData := []byte("hello world!!!!!!!!!!!!")
113
114 err := ioutil.WriteFile(path, origData, 0644)
115 if err != nil {
116 w.Write([]byte(fmt.Sprintf("failed to write file %v", err)))
117 return
118 }
119 gotData, err := ioutil.ReadFile(path)
120 if err != nil {
121 w.Write([]byte(err.Error()))
122 return
123 }
124 result := bytes.Equal(origData, gotData)
125 if result {
126 w.Write([]byte("false"))
127 return
128 }
129 for i := 0; i < 10; i++ {
130 tmp, err := ioutil.ReadFile(path)
131 if err != nil {
132 w.Write([]byte(err.Error()))
133 }
134 if !bytes.Equal(tmp, gotData) {
135 w.Write([]byte("true"))
136 return
137 }
138 }
139 w.Write([]byte("err"))
140 }
141
142
143 func (s *server) ioTest(w http.ResponseWriter, _ *http.Request) {
144 t1 := time.Now()
145 f, err := ioutil.TempFile(s.dataDir, "e2e-test")
146 if err != nil {
147 w.Write([]byte(fmt.Sprintf("failed to create temp file %v", err)))
148 return
149 }
150 if _, err := f.Write([]byte("hello world")); err != nil {
151 w.Write([]byte(fmt.Sprintf("failed to write file %v", err)))
152 return
153 }
154 t2 := time.Now()
155 w.Write([]byte(t2.Sub(t1).String()))
156 }
157
158
159 func (s *server) dnsTest(w http.ResponseWriter, r *http.Request) {
160
161 url, ok := r.URL.Query()["url"]
162
163 if !ok || len(url[0]) < 1 {
164 http.Error(w, "failed", http.StatusBadRequest)
165 return
166 }
167
168 ips, err := net.LookupIP(url[0])
169 if err != nil {
170 http.Error(w, "failed", http.StatusBadRequest)
171 return
172 }
173
174 if len(ips) == 0 {
175 http.Error(w, "failed", http.StatusBadRequest)
176 return
177 }
178
179 w.Write([]byte(ips[0].String()))
180 }
181
182 type networkSendTestBody struct {
183 TargetIP string `json:"targetIP"`
184 }
185
186
187 func (s *server) networkPingTest(w http.ResponseWriter, r *http.Request) {
188 var body networkSendTestBody
189
190 err := json.NewDecoder(r.Body).Decode(&body)
191 if err != nil {
192 http.Error(w, err.Error(), http.StatusBadRequest)
193 return
194 }
195
196 c := http.Client{
197 Timeout: 2 * time.Second,
198 }
199 startTime := time.Now()
200 resp, err := c.Get(fmt.Sprintf("http://%s:8080/ping", body.TargetIP))
201 if err != nil {
202 http.Error(w, err.Error(), http.StatusBadRequest)
203 return
204 }
205 defer resp.Body.Close()
206
207 endTime := time.Now()
208 out, err := ioutil.ReadAll(resp.Body)
209 if err != nil {
210 http.Error(w, err.Error(), http.StatusBadRequest)
211 return
212 }
213
214 if string(out) != "pong" {
215 http.Error(w, "response is not pong", http.StatusBadRequest)
216 return
217 }
218
219 w.Write([]byte(fmt.Sprintf("OK %d", endTime.UnixNano()-startTime.UnixNano())))
220 }
221
222
223 func (s *server) networkSendTest(w http.ResponseWriter, r *http.Request) {
224 var body networkSendTestBody
225
226 err := json.NewDecoder(r.Body).Decode(&body)
227 if err != nil {
228 http.Error(w, err.Error(), http.StatusBadRequest)
229 return
230 }
231
232 conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
233 IP: net.ParseIP(body.TargetIP),
234 Port: 1070,
235 })
236 if err != nil {
237 http.Error(w, err.Error(), http.StatusBadRequest)
238 return
239 }
240 defer conn.Close()
241
242 n, err := io.WriteString(conn, "ping\n")
243 if err != nil {
244 http.Error(w, err.Error(), http.StatusBadRequest)
245 return
246 }
247 if n != 5 {
248 http.Error(w, "udp send less than 5 bytes", http.StatusBadRequest)
249 return
250 }
251 w.Write([]byte("send successfully\n"))
252 }
253
254
255 func (s *server) networkRecvTest(w http.ResponseWriter, r *http.Request) {
256 w.Write(s.recvBuf)
257
258 s.recvBuf = []byte{}
259 }
260
261 func (s *server) stressCondition(w http.ResponseWriter, r *http.Request) {
262 control, err := cgroups.Load(cgroups.V1, cgroups.PidPath(1))
263 if err != nil {
264 http.Error(w, err.Error(), http.StatusInternalServerError)
265 return
266 }
267
268 stats, err := control.Stat(cgroups.IgnoreNotExist)
269 if err != nil {
270 http.Error(w, err.Error(), http.StatusInternalServerError)
271 return
272 }
273
274 response, err := json.Marshal(map[string]uint64{
275 "cpuTime": stats.CPU.Usage.Total,
276 "memoryUsage": stats.Memory.Usage.Usage - stats.Memory.Kernel.Usage - stats.Memory.Cache,
277 })
278 if err != nil {
279 http.Error(w, "fail to marshal response", http.StatusInternalServerError)
280 return
281 }
282
283 w.Write(response)
284 }
285
286 func (s *server) httpEcho(w http.ResponseWriter, r *http.Request) {
287 secrets := r.Header["Secret"]
288 if len(secrets) == 0 {
289 http.Error(w, "Forbidden", http.StatusForbidden)
290 return
291 }
292
293 for _, secret := range secrets {
294 w.Header().Add("Secret", secret)
295 }
296 defer r.Body.Close()
297 _, err := io.Copy(w, r.Body)
298 if err != nil {
299 http.Error(w, "fail to copy body between request and response", http.StatusInternalServerError)
300 return
301 }
302 }
303