mirror of https://github.com/chaos-mesh/chaosd.git
RadisChaos: Add Cache Expiration (#175)
* add redis cache expiration Signed-off-by: FingerLeader <wanxfinger@gmail.com> * edit some details Signed-off-by: FingerLeader <wanxfinger@gmail.com> * edit some details Signed-off-by: FingerLeader <wanxfinger@gmail.com> * modify default value of key Signed-off-by: FingerLeader <wanxfinger@gmail.com> * edit some details Signed-off-by: FingerLeader <wanxfinger@gmail.com>
This commit is contained in:
parent
f1df7d3f15
commit
e4cabb4419
|
|
@ -45,6 +45,7 @@ func NewRedisAttackCommand(uid *string) *cobra.Command {
|
|||
NewRedisSentinelStopCommand(dep, options),
|
||||
NewRedisCachePenetrationCommand(dep, options),
|
||||
NewRedisCacheLimitCommand(dep, options),
|
||||
NewRedisCacheExpirationCommand(dep, options),
|
||||
)
|
||||
|
||||
return cmd
|
||||
|
|
@ -60,7 +61,7 @@ func NewRedisSentinelRestartCommand(dep fx.Option, options *core.RedisCommand) *
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "")
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "The address of redis server")
|
||||
cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The password of server")
|
||||
cmd.Flags().StringVarP(&options.Conf, "conf", "c", "", "The config of Redis server")
|
||||
cmd.Flags().BoolVarP(&options.FlushConfig, "flush-config", "", true, " Force Sentinel to rewrite its configuration on disk")
|
||||
|
|
@ -80,7 +81,7 @@ func NewRedisSentinelStopCommand(dep fx.Option, options *core.RedisCommand) *cob
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "")
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "The address of redis server")
|
||||
cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The password of server")
|
||||
cmd.Flags().StringVarP(&options.Conf, "conf", "c", "", "The config path of Redis server")
|
||||
cmd.Flags().BoolVarP(&options.FlushConfig, "flush-config", "", true, "Force Sentinel to rewrite its configuration on disk")
|
||||
|
|
@ -99,7 +100,7 @@ func NewRedisCachePenetrationCommand(dep fx.Option, options *core.RedisCommand)
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "")
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "The address of redis server")
|
||||
cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The password of server")
|
||||
cmd.Flags().IntVarP(&options.RequestNum, "request-num", "", 0, "The number of requests")
|
||||
|
||||
|
|
@ -116,7 +117,7 @@ func NewRedisCacheLimitCommand(dep fx.Option, options *core.RedisCommand) *cobra
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "")
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "The address of redis server")
|
||||
cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The password of server")
|
||||
cmd.Flags().StringVarP(&options.CacheSize, "size", "s", "0", "The size of cache")
|
||||
cmd.Flags().StringVarP(&options.Percent, "percent", "", "", "The percentage of maxmemory")
|
||||
|
|
@ -124,6 +125,25 @@ func NewRedisCacheLimitCommand(dep fx.Option, options *core.RedisCommand) *cobra
|
|||
return cmd
|
||||
}
|
||||
|
||||
func NewRedisCacheExpirationCommand(dep fx.Option, options *core.RedisCommand) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "cache-expiration",
|
||||
Short: "expire keys in Redis",
|
||||
Run: func(*cobra.Command, []string) {
|
||||
options.Action = core.RedisCacheExpirationAction
|
||||
utils.FxNewAppWithoutLog(dep, fx.Invoke(redisAttackF)).Run()
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().StringVarP(&options.Addr, "addr", "a", "", "The address of redis server")
|
||||
cmd.Flags().StringVarP(&options.Password, "password", "p", "", "The password of server")
|
||||
cmd.Flags().StringVarP(&options.Key, "key", "k", "", "The key to be set a expiration, default expire all keys")
|
||||
cmd.Flags().StringVarP(&options.Expiration, "expiration", "", "0", `The expiration of the key. A expiration string should be able to be converted to a time duration, such as "5s" or "30m"`)
|
||||
cmd.Flags().StringVarP(&options.Option, "option", "", "", "The additional options of expiration, only NX, XX, GT, LT supported")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func redisAttackF(chaos *chaosd.Server, options *core.RedisCommand) {
|
||||
if err := options.Validate(); err != nil {
|
||||
utils.ExitWithError(utils.ExitBadArgs, err)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,13 @@ const (
|
|||
RedisSentinelStopAction = "stop"
|
||||
RedisCachePenetrationAction = "penetration"
|
||||
RedisCacheLimitAction = "cacheLimit"
|
||||
RedisCacheExpirationAction = "expiration"
|
||||
)
|
||||
|
||||
var _ AttackConfig = &RedisCommand{}
|
||||
var (
|
||||
_ AttackConfig = &RedisCommand{}
|
||||
ValidOptions = map[string]bool{"XX": true, "NX": true, "GT": true, "LT": true}
|
||||
)
|
||||
|
||||
type RedisCommand struct {
|
||||
CommonAttackConfig
|
||||
|
|
@ -39,6 +43,9 @@ type RedisCommand struct {
|
|||
RequestNum int `json:"requestNum,omitempty"`
|
||||
CacheSize string `json:"cacheSize,omitempty"`
|
||||
Percent string `json:"percent,omitempty"`
|
||||
Key string `json:"key,omitempty"`
|
||||
Expiration string `json:"expiration,omitempty"`
|
||||
Option string `json:"option,omitempty"`
|
||||
|
||||
OriginCacheSize string `json:"originCacheSize,omitempty"`
|
||||
}
|
||||
|
|
@ -60,6 +67,10 @@ func (r *RedisCommand) Validate() error {
|
|||
if r.CacheSize != "0" && r.Percent != "" {
|
||||
return errors.New("only one of cachesize and percent can be set")
|
||||
}
|
||||
case RedisCacheExpirationAction:
|
||||
if _, ok := ValidOptions[r.Option]; ok {
|
||||
return errors.New("option invalid")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
"math"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/pingcap/errors"
|
||||
|
|
@ -31,6 +32,10 @@ var RedisAttack AttackType = redisAttack{}
|
|||
|
||||
const (
|
||||
STATUSOK = "OK"
|
||||
OPTIONNX = "NX"
|
||||
OPTIONXX = "XX"
|
||||
OPTIONGT = "GT"
|
||||
OPTIONLT = "LT"
|
||||
)
|
||||
|
||||
func (redisAttack) Attack(options core.AttackConfig, env Environment) error {
|
||||
|
|
@ -97,6 +102,9 @@ func (redisAttack) Attack(options core.AttackConfig, env Environment) error {
|
|||
if result != STATUSOK {
|
||||
return errors.WithStack(errors.Errorf("redis command status is %s", result))
|
||||
}
|
||||
|
||||
case core.RedisCacheExpirationAction:
|
||||
return env.Chaos.expireKeys(attack, cli)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -170,3 +178,53 @@ func (s *Server) recoverSentinelStop(attack *core.RedisCommand) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) expireKeys(attack *core.RedisCommand, cli *redis.Client) error {
|
||||
|
||||
expiration, err := time.ParseDuration(attack.Expiration)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if attack.Key == "" {
|
||||
// Get all keys from the server
|
||||
allKeys, err := cli.Keys(cli.Context(), "*").Result()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
for _, key := range allKeys {
|
||||
result, err := ExpireFunc(cli, key, expiration, attack.Option).Result()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if !result {
|
||||
return errors.WithStack(errors.Errorf("expire failed"))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result, err := ExpireFunc(cli, attack.Key, expiration, attack.Option).Result()
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
if !result {
|
||||
return errors.WithStack(errors.Errorf("expire failed"))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ExpireFunc(cli *redis.Client, key string, expiration time.Duration, option string) *redis.BoolCmd {
|
||||
switch option {
|
||||
case OPTIONNX:
|
||||
return cli.ExpireNX(cli.Context(), key, expiration)
|
||||
case OPTIONXX:
|
||||
return cli.ExpireXX(cli.Context(), key, expiration)
|
||||
case OPTIONGT:
|
||||
return cli.ExpireGT(cli.Context(), key, expiration)
|
||||
case OPTIONLT:
|
||||
return cli.ExpireLT(cli.Context(), key, expiration)
|
||||
default:
|
||||
return cli.Expire(cli.Context(), key, expiration)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue