Skip to content

Commit 39c7c76

Browse files
authored
Simulate port is already allocated (#62) (#67)
Signed-off-by: Luanqi <[email protected]>
1 parent 72b06cc commit 39c7c76

File tree

5 files changed

+180
-1
lines changed

5 files changed

+180
-1
lines changed

cmd/attack/network.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func NewNetworkAttackCommand() *cobra.Command {
4545
NewNetworkCorruptCommand(dep, options),
4646
NetworkDuplicateCommand(dep, options),
4747
NetworkDNSCommand(dep, options),
48+
NewNetworkPortOccupiedCommand(dep, options),
4849
)
4950

5051
return cmd
@@ -201,3 +202,19 @@ func commonNetworkAttackFunc(options *core.NetworkCommand, chaos *chaosd.Server)
201202

202203
utils.NormalExit(fmt.Sprintf("Attack network successfully, uid: %s", uid))
203204
}
205+
206+
func NewNetworkPortOccupiedCommand(dep fx.Option, options *core.NetworkCommand) *cobra.Command {
207+
cmd := &cobra.Command{
208+
Use: "port",
209+
Short: "attack network port",
210+
211+
Run: func(cmd *cobra.Command, args []string) {
212+
options.Action = core.NetworkPortOccupied
213+
options.CompleteDefaults()
214+
utils.FxNewAppWithoutLog(dep, fx.Invoke(commonNetworkAttackFunc)).Run()
215+
},
216+
}
217+
218+
cmd.Flags().StringVarP(&options.Port, "port", "p", "", "this specified port is to occupied")
219+
return cmd
220+
}

cmd/main

59.7 MB
Binary file not shown.

pkg/core/network.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ type NetworkCommand struct {
4343

4444
// used for DNS attack
4545
DNSServer string
46+
Port string
47+
PortPid int32
4648
DNSIp string
4749
DNSHost string
4850
}
@@ -55,6 +57,7 @@ const (
5557
NetworkCorruptAction = "corrupt"
5658
NetworkDuplicateAction = "duplicate"
5759
NetworkDNSAction = "dns"
60+
NetworkPortOccupied = "occupied"
5861
)
5962

6063
func (n *NetworkCommand) Validate() error {
@@ -68,6 +71,8 @@ func (n *NetworkCommand) Validate() error {
6871
return n.validNetworkCommon()
6972
case NetworkDNSAction:
7073
return n.validNetworkDNS()
74+
case NetworkPortOccupied:
75+
return n.validNetworkOccupied()
7176
default:
7277
return errors.Errorf("network action %s not supported", n.Action)
7378
}
@@ -143,6 +148,13 @@ func (n *NetworkCommand) validNetworkDNS() error {
143148
return nil
144149
}
145150

151+
func (n *NetworkCommand) validNetworkOccupied() error {
152+
if len(n.Port) == 0 {
153+
return errors.New("port is required")
154+
}
155+
return nil
156+
}
157+
146158
func (n *NetworkCommand) CompleteDefaults() {
147159
switch n.Action {
148160
case NetworkDelayAction:

pkg/server/chaosd/network.go

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ import (
2323
"os/exec"
2424
"regexp"
2525
"strings"
26+
"syscall"
27+
28+
"github.com/chaos-mesh/chaos-mesh/pkg/bpm"
29+
"github.com/shirou/gopsutil/process"
2630

2731
"go.uber.org/zap"
2832

@@ -59,6 +63,9 @@ func (networkAttack) Attack(options core.AttackConfig, env Environment) (err err
5963
}
6064
}
6165

66+
case core.NetworkPortOccupied:
67+
return env.Chaos.applyPortOccupied(attack)
68+
6269
case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction:
6370
if attack.NeedApplyIPSet() {
6471
ipsetName, err = env.Chaos.applyIPSet(attack, env.AttackUid)
@@ -316,7 +323,8 @@ func (networkAttack) Recover(exp core.Experiment, env Environment) error {
316323
}
317324
}
318325
return env.Chaos.recoverDNSServer(attack)
319-
326+
case core.NetworkPortOccupied:
327+
return env.Chaos.recoverPortOccupied(attack, env.AttackUid)
320328
case core.NetworkDelayAction, core.NetworkLossAction, core.NetworkCorruptAction, core.NetworkDuplicateAction:
321329
if attack.NeedApplyIPSet() {
322330
if err := env.Chaos.recoverIPSet(env.AttackUid); err != nil {
@@ -411,6 +419,83 @@ func (s *Server) recoverDNSServer(attack *core.NetworkCommand) error {
411419
return nil
412420
}
413421

422+
func (s *Server) applyPortOccupied(attack *core.NetworkCommand) error {
423+
424+
if len(attack.Port) == 0 {
425+
return nil
426+
}
427+
428+
flag, err := checkPortIsListened(attack.Port)
429+
if err != nil {
430+
if flag {
431+
return errors.Errorf("port %s has been occupied", attack.Port)
432+
}
433+
return errors.WithStack(err)
434+
}
435+
436+
if flag {
437+
return errors.Errorf("port %s has been occupied", attack.Port)
438+
}
439+
440+
args := fmt.Sprintf("-p=%s", attack.Port)
441+
cmd := bpm.DefaultProcessBuilder("PortOccupyTool", args).Build()
442+
443+
cmd.Cmd.SysProcAttr = &syscall.SysProcAttr{}
444+
445+
backgroundProcessManager := bpm.NewBackgroundProcessManager()
446+
err = backgroundProcessManager.StartProcess(cmd)
447+
if err != nil {
448+
return errors.WithStack(err)
449+
}
450+
451+
attack.PortPid = int32(cmd.Process.Pid)
452+
453+
return nil
454+
}
455+
456+
func checkPortIsListened(port string) (bool, error) {
457+
checkStatement := fmt.Sprintf("lsof -i:%s | awk '{print $2}' | grep -v PID", port)
458+
cmd := exec.Command("sh", "-c", checkStatement)
459+
460+
stdout, err := cmd.CombinedOutput()
461+
if err != nil {
462+
if err.Error() == "exit status 1" && string(stdout) == "" {
463+
return false, nil
464+
}
465+
log.Error(cmd.String()+string(stdout), zap.Error(err))
466+
return true, errors.WithStack(err)
467+
}
468+
469+
if string(stdout) == "" {
470+
return false, nil
471+
}
472+
return true, nil
473+
}
474+
475+
func (s *Server) recoverPortOccupied(attack *core.NetworkCommand, uid string) error {
476+
477+
proc, err := process.NewProcess(attack.PortPid)
478+
if err != nil {
479+
return err
480+
}
481+
482+
procName, err := proc.Name()
483+
if err != nil {
484+
return err
485+
}
486+
487+
if !strings.Contains(procName, "PortOccupyTool") {
488+
log.Warn("the process is not PortOccupyTool, maybe it is killed by manual")
489+
return nil
490+
}
491+
492+
if err := proc.Kill(); err != nil {
493+
log.Error("the port occupy process kill failed", zap.Error(err))
494+
return err
495+
}
496+
return nil
497+
}
498+
414499
func (s *Server) recoverEtcHosts(attack *core.NetworkCommand, uid string) error {
415500
cmd := "mv /etc/hosts.chaosd." + uid + " /etc/hosts"
416501
recoverCmd := exec.Command("/bin/bash", "-c", cmd) // #nosec

tools/PortOccupyTool.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2020 Chaos Mesh Authors.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package main
15+
16+
import (
17+
"fmt"
18+
"net/http"
19+
20+
"github.com/pingcap/errors"
21+
"github.com/pingcap/log"
22+
"github.com/spf13/cobra"
23+
"go.uber.org/zap"
24+
)
25+
26+
func PortOccupyTool() error {
27+
var Port string
28+
var rootCmd = &cobra.Command{
29+
Use: "http server start",
30+
Short: "http server start",
31+
Run: func(cmd *cobra.Command, args []string) {
32+
startHttp(Port)
33+
},
34+
}
35+
36+
rootCmd.Flags().StringVarP(&Port, "port", "p", "", "port to occupy")
37+
if err := rootCmd.Execute(); err != nil {
38+
return errors.WithStack(err)
39+
}
40+
41+
return nil
42+
}
43+
44+
func generateHttpPort(port string) string {
45+
s := fmt.Sprintf(":%s", port)
46+
return s
47+
}
48+
49+
func startHttp(porttoOccupy string) {
50+
51+
s := generateHttpPort(porttoOccupy)
52+
53+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
54+
fmt.Fprintf(w, "Hello cmd!")
55+
})
56+
if err := http.ListenAndServe(s, nil); err != nil {
57+
log.Error("ListenAndServe", zap.Error(err))
58+
}
59+
}
60+
61+
func main() {
62+
if err := PortOccupyTool(); err != nil {
63+
log.Error("PortOccupyTool run fail", zap.Error(err))
64+
}
65+
}

0 commit comments

Comments
 (0)