add percentage of disk option in disk fill (#46)

This commit is contained in:
Andrewmatilde 2021-04-16 10:16:49 +08:00 committed by GitHub
parent 721fc1398a
commit 618b8eaebe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 22 deletions

View File

@ -67,7 +67,7 @@ func NewDiskWritePayloadCommand(dep fx.Option, options *core.DiskCommand) *cobra
},
}
cmd.Flags().Uint64VarP(&options.Size, "size", "s", 0,
cmd.Flags().StringVarP(&options.Size, "size", "s", "",
"'size' specifies how many data will fill in the file path with unit MB.")
cmd.Flags().StringVarP(&options.Path, "path", "p", "/dev/null",
"'path' specifies the location to fill data in.\n"+
@ -86,7 +86,7 @@ func NewDiskReadPayloadCommand(dep fx.Option, options *core.DiskCommand) *cobra.
},
}
cmd.Flags().Uint64VarP(&options.Size, "size", "s", 0,
cmd.Flags().StringVarP(&options.Size, "size", "s", "",
"'size' specifies how many data will read from the file path with unit MB.")
cmd.Flags().StringVarP(&options.Path, "path", "p", "",
"'path' specifies the location to read data.\n"+
@ -105,11 +105,13 @@ func NewDiskFillCommand(dep fx.Option, options *core.DiskCommand) *cobra.Command
},
}
cmd.Flags().Uint64VarP(&options.Size, "size", "s", 0,
cmd.Flags().StringVarP(&options.Size, "size", "s", "",
"'size' specifies how many data will fill in the file path with unit MB.")
cmd.Flags().StringVarP(&options.Path, "path", "p", "",
"'path' specifies the location to fill data in.\n"+
"If path not provided, a temp file will be generated and deleted immediately after data filled in or allocated")
cmd.Flags().StringVarP(&options.Percent, "percent", "c", "",
"'percent' how many percent data of disk will fill in the file path")
cmd.Flags().BoolVarP(&options.FillByFallocate, "fallocate", "f", true, "fill disk by fallocate instead of dd")
commonFlags(cmd, &options.CommonAttackConfig)
return cmd

View File

@ -15,6 +15,7 @@ package command
import (
"os"
"strconv"
"testing"
"go.uber.org/fx"
@ -43,7 +44,7 @@ func TestServer_DiskFill(t *testing.T) {
Action: core.DiskFillAction,
Kind: core.DiskAttack,
},
Size: 1024,
Size: "1024",
Path: "temp",
FillByFallocate: true,
},
@ -55,7 +56,7 @@ func TestServer_DiskFill(t *testing.T) {
Action: core.DiskFillAction,
Kind: core.DiskAttack,
},
Size: 24,
Size: "24",
Path: "temp",
FillByFallocate: false,
},
@ -85,8 +86,10 @@ func TestServer_DiskFill(t *testing.T) {
return
}
if uint64(stat.Size()) != tt.command.Size*1024*1024 {
t.Errorf("DiskFill() size %v, expect %d", stat.Size(), tt.command.Size*1024*1024)
size, _ := strconv.ParseUint(tt.command.Size, 10, 0)
if uint64(stat.Size()) != size*1024*1024 {
t.Errorf("DiskFill() size %v, expect %d", stat.Size(), size*1024*1024)
return
}
os.Remove(tt.command.Path)
@ -109,7 +112,7 @@ func TestServer_DiskPayload(t *testing.T) {
Action: core.DiskWritePayloadAction,
Kind: core.DiskAttack,
},
Size: 24,
Size: "24",
Path: "temp",
},
wantErr: false,
@ -120,7 +123,7 @@ func TestServer_DiskPayload(t *testing.T) {
Action: core.DiskReadPayloadAction,
Kind: core.DiskAttack,
},
Size: 24,
Size: "24",
Path: "temp",
},
wantErr: false,

View File

@ -16,6 +16,7 @@ package core
import (
"encoding/json"
"fmt"
"strconv"
)
const (
@ -27,18 +28,27 @@ const (
type DiskCommand struct {
CommonAttackConfig
Size uint64 `json:"size"`
Size string `json:"size"`
Path string `json:"path"`
Percent string `json:"percent"`
FillByFallocate bool `json:"fill_by_fallocate"`
}
var _ AttackConfig = &DiskCommand{}
func (d DiskCommand) Validate() error {
if d.Action == DiskFillAction || d.Action == DiskWritePayloadAction || d.Action == DiskReadPayloadAction {
return nil
func (d *DiskCommand) Validate() error {
if d.Percent == "" && d.Size == "" {
return fmt.Errorf("one of percent and size must not be empty, DiskCommand : %v", d)
}
return fmt.Errorf("invalid disk attack action %v", d.Action)
if d.FillByFallocate && (d.Size == "0" || (d.Size == "" && d.Percent == "0")) {
return fmt.Errorf("fallocate not suppurt 0 size or 0 percent data, "+
"if you want allocate a 0 size file please set fallocate=false, DiskCommand : %v", d)
}
_, err := strconv.ParseUint(d.Percent, 10, 0)
if d.Size == "" && err != nil {
return fmt.Errorf("unsupport percent : %s, DiskCommand : %v", d.Percent, d)
}
return nil
}
func (d DiskCommand) RecoverData() string {

View File

@ -18,7 +18,10 @@ import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"syscall"
"github.com/pingcap/errors"
"github.com/pingcap/log"
@ -38,18 +41,18 @@ func (disk diskAttack) Attack(options core.AttackConfig, env Environment) (err e
attack := options.(*core.DiskCommand)
if options.String() == core.DiskFillAction {
return disk.attackDiskFill(env.AttackUid, attack)
return disk.attackDiskFill(attack)
}
return disk.attackDiskPayload(env.AttackUid, attack)
return disk.attackDiskPayload(attack)
}
func (diskAttack) attackDiskPayload(uid string, payload *core.DiskCommand) error {
func (diskAttack) attackDiskPayload(payload *core.DiskCommand) error {
switch payload.Action {
case core.DiskWritePayloadAction:
if payload.Path == "" {
payload.Path = "/dev/null"
}
cmd := exec.Command("bash", "-c", fmt.Sprintf(DDWritePayloadCommand, payload.Path, "1M", strconv.FormatUint(payload.Size, 10)))
cmd := exec.Command("bash", "-c", fmt.Sprintf(DDWritePayloadCommand, payload.Path, "1M", payload.Size))
output, err := cmd.CombinedOutput()
if err != nil {
@ -64,7 +67,7 @@ func (diskAttack) attackDiskPayload(uid string, payload *core.DiskCommand) error
log.Error(fmt.Sprintf("payload action: %s", payload.Action), zap.Error(err))
return err
}
cmd := exec.Command("bash", "-c", fmt.Sprintf(DDReadPayloadCommand, payload.Path, "1M", strconv.FormatUint(payload.Size, 10)))
cmd := exec.Command("bash", "-c", fmt.Sprintf(DDReadPayloadCommand, payload.Path, "1M", payload.Size))
output, err := cmd.CombinedOutput()
if err != nil {
@ -83,7 +86,7 @@ func (diskAttack) attackDiskPayload(uid string, payload *core.DiskCommand) error
const DDFillCommand = "dd if=/dev/zero of=%s bs=%s count=%s iflag=fullblock"
const DDFallocateCommand = "fallocate -l %sM %s"
func (diskAttack) attackDiskFill(uid string, fill *core.DiskCommand) error {
func (diskAttack) attackDiskFill(fill *core.DiskCommand) error {
if fill.Path == "" {
tempFile, err := ioutil.TempFile("", "example")
if err != nil {
@ -113,11 +116,32 @@ func (diskAttack) attackDiskFill(uid string, fill *core.DiskCommand) error {
}
var cmd *exec.Cmd
if fill.Size != "" {
fill.Size = strings.Trim(fill.Size, " ")
} else if fill.Percent != "" {
fill.Percent = strings.Trim(fill.Percent, " ")
percent, err := strconv.ParseUint(fill.Percent, 10, 0)
if err != nil {
log.Error(fmt.Sprintf(" unexcepted err when parsing disk percent '%s'", fill.Percent), zap.Error(err))
return err
}
dir := filepath.Dir(fill.Path)
s := syscall.Statfs_t{}
err = syscall.Statfs(dir, &s)
if err != nil {
log.Error(fmt.Sprintf("unexpected err when using syscall.Statfs"), zap.Error(err))
return err
}
reservedBlocks := s.Bfree - s.Bavail
totalM := uint64(s.Frsize) * (s.Blocks - reservedBlocks) / 1024 / 1024
fill.Size = strconv.FormatUint(totalM*percent/100, 10)
}
if fill.FillByFallocate {
cmd = exec.Command("bash", "-c", fmt.Sprintf(DDFallocateCommand, strconv.FormatUint(fill.Size, 10), fill.Path))
cmd = exec.Command("bash", "-c", fmt.Sprintf(DDFallocateCommand, fill.Size, fill.Path))
} else {
//1M means the block size. The bytes size dd read | write is (block size) * (size).
cmd = exec.Command("bash", "-c", fmt.Sprintf(DDFillCommand, fill.Path, "1M", strconv.FormatUint(fill.Size, 10)))
cmd = exec.Command("bash", "-c", fmt.Sprintf(DDFillCommand, fill.Path, "1M", fill.Size))
}
output, err := cmd.CombinedOutput()