-
Notifications
You must be signed in to change notification settings - Fork 198
/
Copy pathcommand.go
123 lines (113 loc) · 2.99 KB
/
command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
package chaos
import (
"context"
"strings"
"time"
"github.com/alexei-led/pumba/pkg/container"
"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
const (
// Re2Prefix re2 regexp string prefix
Re2Prefix = "re2:"
)
var (
// DockerClient Docker client instance
DockerClient container.Client
)
// Command chaos command
type Command interface {
Run(ctx context.Context, random bool) error
}
// GlobalParams global parameters passed through CLI flags
type GlobalParams struct {
Random bool
Labels []string
Pattern string
Names []string
Interval time.Duration
DryRun bool
SkipErrors bool
}
// ParseGlobalParams parse global parameters
func ParseGlobalParams(c *cli.Context) (*GlobalParams, error) {
// get random flag
random := c.GlobalBool("random")
// get labels
labels := c.GlobalStringSlice("label")
// get dry-run mode
dryRun := c.GlobalBool("dry-run")
// get skip error flag
skipError := c.GlobalBool("skip-error")
// get names or pattern
names, pattern := getNamesOrPattern(c)
// get global chaos interval
interval := c.GlobalDuration("interval")
return &GlobalParams{
Random: random,
Labels: labels,
Pattern: pattern,
Names: names,
DryRun: dryRun,
SkipErrors: skipError,
Interval: interval,
}, nil
}
// get names list of filter pattern from command line
func getNamesOrPattern(c *cli.Context) ([]string, string) {
var names []string
pattern := ""
// get container names or pattern: no Args means ALL containers
if c.Args().Present() {
// more than one argument, assume that this a list of names
if len(c.Args()) > 1 {
names = c.Args()
log.WithField("names", names).Debug("using names")
} else {
first := c.Args().First()
if strings.HasPrefix(first, Re2Prefix) {
pattern = strings.Trim(first, Re2Prefix)
log.WithField("pattern", pattern).Debug("using pattern")
} else {
names = append(names, first)
log.WithField("names", names).Debug("using names")
}
}
}
return names, pattern
}
// RunChaosCommand run chaos command in go routine
func RunChaosCommand(topContext context.Context, command Command, params *GlobalParams) error {
// create Time channel for specified interval
var tick <-chan time.Time
if params.Interval == 0 {
tick = time.NewTimer(params.Interval).C
} else {
tick = time.NewTicker(params.Interval).C
}
// handle the 'chaos' command
ctx, cancel := context.WithCancel(topContext)
// cancel current context on exit
defer cancel()
// run chaos command
for {
// run chaos function
if err := command.Run(ctx, params.Random); err != nil {
if !params.SkipErrors {
return errors.Wrap(err, "error running chaos command")
}
log.WithError(err).Warn("skipping error")
}
// wait for next timer tick or cancel
select {
case <-topContext.Done():
return nil // not to leak the goroutine
case <-tick:
if params.Interval == 0 {
return nil // not to leak the goroutine
}
log.Debug("next chaos execution (tick) ...")
}
}
}