mirror of https://github.com/chaos-mesh/chaosd.git
Merge branch 'main' into file
This commit is contained in:
commit
684c9f93b2
|
|
@ -48,9 +48,10 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
|
|
||||||
# download tools
|
# download tools
|
||||||
curl -fsSL -o byteman.tar.gz https://mirrors.chaos-mesh.org/latest/byteman.tar.gz
|
BYTEMAN_DIR=byteman-chaos-mesh-download-v4.0.18-0.9
|
||||||
|
curl -fsSL -o ${BYTEMAN_DIR}.tar.gz https://mirrors.chaos-mesh.org/${BYTEMAN_DIR}.tar.gz
|
||||||
curl -fsSL -o stress-ng https://mirrors.chaos-mesh.org/latest/stress-ng
|
curl -fsSL -o stress-ng https://mirrors.chaos-mesh.org/latest/stress-ng
|
||||||
tar zxvf byteman.tar.gz
|
tar zxvf ${BYTEMAN_DIR}.tar.gz
|
||||||
chmod +x ./stress-ng
|
chmod +x ./stress-ng
|
||||||
|
|
||||||
# prepare package
|
# prepare package
|
||||||
|
|
@ -58,7 +59,7 @@ jobs:
|
||||||
mkdir chaosd-latest-linux-amd64/tools
|
mkdir chaosd-latest-linux-amd64/tools
|
||||||
mv bin/chaosd chaosd-latest-linux-amd64/
|
mv bin/chaosd chaosd-latest-linux-amd64/
|
||||||
mv bin/PortOccupyTool chaosd-latest-linux-amd64/tools/
|
mv bin/PortOccupyTool chaosd-latest-linux-amd64/tools/
|
||||||
mv byteman chaosd-latest-linux-amd64/tools/
|
mv ${BYTEMAN_DIR} chaosd-latest-linux-amd64/tools/byteman
|
||||||
mv stress-ng chaosd-latest-linux-amd64/tools/
|
mv stress-ng chaosd-latest-linux-amd64/tools/
|
||||||
|
|
||||||
# upload package
|
# upload package
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,10 @@ jobs:
|
||||||
GIT_TAG=${GITHUB_REF##*/}
|
GIT_TAG=${GITHUB_REF##*/}
|
||||||
|
|
||||||
# download tools
|
# download tools
|
||||||
curl -fsSL -o byteman.tar.gz https://mirrors.chaos-mesh.org/latest/byteman.tar.gz
|
BYTEMAN_DIR=byteman-chaos-mesh-download-v4.0.18-0.9
|
||||||
|
curl -fsSL -o ${BYTEMAN_DIR}.tar.gz https://mirrors.chaos-mesh.org/${BYTEMAN_DIR}.tar.gz
|
||||||
curl -fsSL -o stress-ng https://mirrors.chaos-mesh.org/latest/stress-ng
|
curl -fsSL -o stress-ng https://mirrors.chaos-mesh.org/latest/stress-ng
|
||||||
tar zxvf byteman.tar.gz
|
tar zxvf ${BYTEMAN_DIR}.tar.gz
|
||||||
chmod +x ./stress-ng
|
chmod +x ./stress-ng
|
||||||
|
|
||||||
# prepare package
|
# prepare package
|
||||||
|
|
@ -59,7 +60,7 @@ jobs:
|
||||||
mkdir chaosd-${GIT_TAG}-linux-amd64/tools
|
mkdir chaosd-${GIT_TAG}-linux-amd64/tools
|
||||||
mv bin/chaosd chaosd-${GIT_TAG}-linux-amd64/
|
mv bin/chaosd chaosd-${GIT_TAG}-linux-amd64/
|
||||||
mv bin/PortOccupyTool chaosd-${GIT_TAG}-linux-amd64/tools/
|
mv bin/PortOccupyTool chaosd-${GIT_TAG}-linux-amd64/tools/
|
||||||
mv byteman chaosd-${GIT_TAG}-linux-amd64/tools/
|
mv ${BYTEMAN_DIR} chaosd-${GIT_TAG}-linux-amd64/tools/byteman
|
||||||
mv stress-ng chaosd-${GIT_TAG}-linux-amd64/tools/
|
mv stress-ng chaosd-${GIT_TAG}-linux-amd64/tools/
|
||||||
|
|
||||||
# upload package
|
# upload package
|
||||||
|
|
|
||||||
101
pkg/core/jvm.go
101
pkg/core/jvm.go
|
|
@ -23,6 +23,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// jvm action
|
||||||
JVMLatencyAction = "latency"
|
JVMLatencyAction = "latency"
|
||||||
JVMExceptionAction = "exception"
|
JVMExceptionAction = "exception"
|
||||||
JVMReturnAction = "return"
|
JVMReturnAction = "return"
|
||||||
|
|
@ -30,21 +31,56 @@ const (
|
||||||
JVMGCAction = "gc"
|
JVMGCAction = "gc"
|
||||||
JVMRuleFileAction = "rule-file"
|
JVMRuleFileAction = "rule-file"
|
||||||
JVMRuleDataAction = "rule-data"
|
JVMRuleDataAction = "rule-data"
|
||||||
|
|
||||||
|
// for action 'gc' and 'stress'
|
||||||
|
GCHelper = "org.chaos_mesh.byteman.helper.GCHelper"
|
||||||
|
StressHelper = "org.chaos_mesh.byteman.helper.StressHelper"
|
||||||
|
|
||||||
|
// the trigger point for 'gc' and 'stress'
|
||||||
|
TriggerClass = "org.chaos_mesh.chaos_agent.TriggerThread"
|
||||||
|
TriggerMethod = "triggerFunc"
|
||||||
|
)
|
||||||
|
|
||||||
|
// byteman rule template
|
||||||
|
const (
|
||||||
|
SimpleRuleTemplate = `
|
||||||
|
RULE {{.Name}}
|
||||||
|
CLASS {{.Class}}
|
||||||
|
METHOD {{.Method}}
|
||||||
|
AT ENTRY
|
||||||
|
IF true
|
||||||
|
DO
|
||||||
|
{{.Do}};
|
||||||
|
ENDRULE
|
||||||
|
`
|
||||||
|
|
||||||
|
CompleteRuleTemplate = `
|
||||||
|
RULE {{.Name}}
|
||||||
|
CLASS {{.Class}}
|
||||||
|
METHOD {{.Method}}
|
||||||
|
HELPER {{.Helper}}
|
||||||
|
AT ENTRY
|
||||||
|
BIND {{.Bind}};
|
||||||
|
IF {{.Condition}}
|
||||||
|
DO
|
||||||
|
{{.Do}};
|
||||||
|
ENDRULE
|
||||||
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
type JVMCommand struct {
|
type JVMCommand struct {
|
||||||
CommonAttackConfig
|
CommonAttackConfig
|
||||||
|
|
||||||
|
JVMCommonSpec
|
||||||
|
|
||||||
|
JVMClassMethodSpec
|
||||||
|
|
||||||
|
JVMStressSpec
|
||||||
|
|
||||||
// rule name, should be unique, and will generate by chaosd automatically
|
// rule name, should be unique, and will generate by chaosd automatically
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
|
||||||
// Java class
|
// fault action, values can be latency, exception, return, stress, gc, rule-file, rule-data
|
||||||
Class string `json:"class,omitempty"`
|
|
||||||
|
|
||||||
// the method in Java class
|
|
||||||
Method string `json:"method,omitempty"`
|
|
||||||
|
|
||||||
// fault action, values can be latency, exception, return, stress
|
|
||||||
Action string `json:"action,omitempty"`
|
Action string `json:"action,omitempty"`
|
||||||
|
|
||||||
// the return value for action 'return'
|
// the return value for action 'return'
|
||||||
|
|
@ -56,35 +92,50 @@ type JVMCommand struct {
|
||||||
// the latency duration for action 'latency'
|
// the latency duration for action 'latency'
|
||||||
LatencyDuration int `json:"latency,omitempty"`
|
LatencyDuration int `json:"latency,omitempty"`
|
||||||
|
|
||||||
// the CPU core number, only set it when action is stress
|
// btm rule file path for action 'rule-file'
|
||||||
CPUCount int `json:"cpu-count,omitempty"`
|
RuleFile string `json:"rule-file,omitempty"`
|
||||||
|
|
||||||
// the memory type to be located, only set it when action is stress, the value can be 'stack' or 'heap'
|
// RuleData used to save the rule file's data, will use it when recover, for action 'rule-data'
|
||||||
MemoryType string `json:"mem-type,omitempty"`
|
RuleData string `json:"rule-data,omitempty"`
|
||||||
|
}
|
||||||
// attach or agent
|
|
||||||
Type string
|
|
||||||
|
|
||||||
|
type JVMCommonSpec struct {
|
||||||
// the port of agent server
|
// the port of agent server
|
||||||
Port int `json:"port,omitempty"`
|
Port int `json:"port,omitempty"`
|
||||||
|
|
||||||
// the pid of Java process which needs to attach
|
// the pid of Java process which need to attach
|
||||||
Pid int `json:"pid,omitempty"`
|
Pid int `json:"pid,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// btm rule file path
|
type JVMClassMethodSpec struct {
|
||||||
RuleFile string `json:"rule-file,omitempty"`
|
// Java class
|
||||||
|
Class string `json:"class,omitempty"`
|
||||||
|
|
||||||
// RuleData used to save the rule file's data, will use it when recover
|
// the method in Java class
|
||||||
RuleData string `json:"rule-data,omitempty"`
|
Method string `json:"method,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// below is only used for template
|
type JVMStressSpec struct {
|
||||||
Do string `json:"-"`
|
// the CPU core number need to use, only set it when action is stress
|
||||||
|
CPUCount int `json:"cpu-count,omitempty"`
|
||||||
|
|
||||||
StressType string `json:"-"`
|
// the memory type need to locate, only set it when action is stress, the value can be 'stack' or 'heap'
|
||||||
|
MemoryType string `json:"mem-type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
StressValueName string `json:"-"`
|
type BytemanTemplateSpec struct {
|
||||||
|
Name string
|
||||||
|
Class string
|
||||||
|
Method string
|
||||||
|
Helper string
|
||||||
|
Bind string
|
||||||
|
Condition string
|
||||||
|
Do string
|
||||||
|
|
||||||
StressValue string `json:"-"`
|
// below is only used for stress template
|
||||||
|
StressType string
|
||||||
|
StressValueName string
|
||||||
|
StressValue string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *JVMCommand) Validate() error {
|
func (j *JVMCommand) Validate() error {
|
||||||
|
|
@ -108,7 +159,7 @@ func (j *JVMCommand) Validate() error {
|
||||||
return errors.New("class not provided")
|
return errors.New("class not provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(j.Method) == 0 {
|
if len(j.JVMClassMethodSpec.Method) == 0 {
|
||||||
return errors.New("method not provided")
|
return errors.New("method not provided")
|
||||||
}
|
}
|
||||||
case JVMRuleFileAction:
|
case JVMRuleFileAction:
|
||||||
|
|
|
||||||
|
|
@ -32,62 +32,86 @@ func TestJVMCommand(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"action not provided",
|
"action not provided",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
Action: "test",
|
Action: "test",
|
||||||
},
|
},
|
||||||
"action test not supported",
|
"action test not supported",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
Action: JVMLatencyAction,
|
Action: JVMLatencyAction,
|
||||||
},
|
},
|
||||||
"class not provided",
|
"class not provided",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
Action: JVMExceptionAction,
|
Action: JVMExceptionAction,
|
||||||
Class: "test",
|
JVMClassMethodSpec: JVMClassMethodSpec{
|
||||||
|
Class: "test",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"method not provided",
|
"method not provided",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
Action: JVMExceptionAction,
|
Action: JVMExceptionAction,
|
||||||
Class: "test",
|
JVMClassMethodSpec: JVMClassMethodSpec{
|
||||||
Method: "test",
|
Class: "test",
|
||||||
|
Method: "test",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
Action: JVMStressAction,
|
Action: JVMStressAction,
|
||||||
},
|
},
|
||||||
"must set one of cpu-count and mem-type",
|
"must set one of cpu-count and mem-type",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
Action: JVMStressAction,
|
Pid: 1234,
|
||||||
CPUCount: 1,
|
},
|
||||||
MemoryType: "heap",
|
Action: JVMStressAction,
|
||||||
|
JVMStressSpec: JVMStressSpec{
|
||||||
|
CPUCount: 1,
|
||||||
|
MemoryType: "heap",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"inject stress on both CPU and memory is not support now",
|
"inject stress on both CPU and memory is not support now",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
&JVMCommand{
|
&JVMCommand{
|
||||||
Pid: 1234,
|
JVMCommonSpec: JVMCommonSpec{
|
||||||
Action: JVMStressAction,
|
Pid: 1234,
|
||||||
CPUCount: 1,
|
},
|
||||||
|
Action: JVMStressAction,
|
||||||
|
JVMStressSpec: JVMStressSpec{
|
||||||
|
CPUCount: 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
@ -29,30 +30,6 @@ import (
|
||||||
"github.com/chaos-mesh/chaosd/pkg/core"
|
"github.com/chaos-mesh/chaosd/pkg/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ruleTemplate = `
|
|
||||||
RULE {{.Name}}
|
|
||||||
CLASS {{.Class}}
|
|
||||||
METHOD {{.Method}}
|
|
||||||
AT ENTRY
|
|
||||||
IF true
|
|
||||||
DO
|
|
||||||
{{.Do}};
|
|
||||||
ENDRULE
|
|
||||||
`
|
|
||||||
|
|
||||||
const stressRuleTemplate = `
|
|
||||||
RULE {{.Name}}
|
|
||||||
STRESS {{.StressType}}
|
|
||||||
{{.StressValueName}} {{.StressValue}}
|
|
||||||
ENDRULE
|
|
||||||
`
|
|
||||||
|
|
||||||
const gcRuleTemplate = `
|
|
||||||
RULE {{.Name}}
|
|
||||||
GC
|
|
||||||
ENDRULE
|
|
||||||
`
|
|
||||||
|
|
||||||
type jvmAttack struct{}
|
type jvmAttack struct{}
|
||||||
|
|
||||||
var JVMAttack AttackType = jvmAttack{}
|
var JVMAttack AttackType = jvmAttack{}
|
||||||
|
|
@ -83,13 +60,25 @@ func (j jvmAttack) Attack(options core.AttackConfig, env Environment) (err error
|
||||||
log.Debug(string(output), zap.Error(err))
|
log.Debug(string(output), zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// submit helper jar
|
||||||
|
bmSubmitCmd := fmt.Sprintf(bmSubmitCommand, attack.Port, "b", fmt.Sprintf("%s/lib/byteman-helper.jar", os.Getenv("BYTEMAN_HOME")))
|
||||||
|
cmd = exec.Command("bash", "-c", bmSubmitCmd)
|
||||||
|
output, err = cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Error(string(output), zap.Error(err))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(output) > 0 {
|
||||||
|
log.Info("submit helper", zap.String("output", string(output)))
|
||||||
|
}
|
||||||
|
|
||||||
// submit rules
|
// submit rules
|
||||||
ruleFile, err := j.generateRuleFile(attack)
|
ruleFile, err := j.generateRuleFile(attack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
bmSubmitCmd := fmt.Sprintf(bmSubmitCommand, attack.Port, "l", ruleFile)
|
bmSubmitCmd = fmt.Sprintf(bmSubmitCommand, attack.Port, "l", ruleFile)
|
||||||
cmd = exec.Command("bash", "-c", bmSubmitCmd)
|
cmd = exec.Command("bash", "-c", bmSubmitCmd)
|
||||||
output, err = cmd.CombinedOutput()
|
output, err = cmd.CombinedOutput()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -127,49 +116,11 @@ func (j jvmAttack) generateRuleFile(attack *core.JVMCommand) (string, error) {
|
||||||
return attack.RuleFile, nil
|
return attack.RuleFile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(attack.Do) == 0 {
|
attack.RuleData, err = generateRuleData(attack)
|
||||||
switch attack.Action {
|
|
||||||
case core.JVMLatencyAction:
|
|
||||||
attack.Do = fmt.Sprintf("Thread.sleep(%d)", attack.LatencyDuration)
|
|
||||||
case core.JVMExceptionAction:
|
|
||||||
attack.Do = fmt.Sprintf("throw new %s", attack.ThrowException)
|
|
||||||
case core.JVMReturnAction:
|
|
||||||
attack.Do = fmt.Sprintf("return %s", attack.ReturnValue)
|
|
||||||
case core.JVMStressAction:
|
|
||||||
if attack.CPUCount > 0 {
|
|
||||||
attack.StressType = "CPU"
|
|
||||||
attack.StressValueName = "CPUCOUNT"
|
|
||||||
attack.StressValue = fmt.Sprintf("%d", attack.CPUCount)
|
|
||||||
} else {
|
|
||||||
attack.StressType = "MEMORY"
|
|
||||||
attack.StressValueName = "MEMORYTYPE"
|
|
||||||
attack.StressValue = attack.MemoryType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
var t *template.Template
|
|
||||||
switch attack.Action {
|
|
||||||
case core.JVMStressAction:
|
|
||||||
t = template.Must(template.New("byteman rule").Parse(stressRuleTemplate))
|
|
||||||
case core.JVMExceptionAction, core.JVMLatencyAction, core.JVMReturnAction:
|
|
||||||
t = template.Must(template.New("byteman rule").Parse(ruleTemplate))
|
|
||||||
case core.JVMGCAction:
|
|
||||||
t = template.Must(template.New("byteman rule").Parse(gcRuleTemplate))
|
|
||||||
default:
|
|
||||||
return "", errors.Errorf("jvm action %s not supported", attack.Action)
|
|
||||||
}
|
|
||||||
if t == nil {
|
|
||||||
return "", errors.Errorf("parse byeman rule template failed")
|
|
||||||
}
|
|
||||||
err = t.Execute(buf, attack)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("executing template", zap.Error(err))
|
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
attack.RuleData = buf.String()
|
|
||||||
|
|
||||||
filename, err := writeDataIntoFile(attack.RuleData, "rule.btm")
|
filename, err := writeDataIntoFile(attack.RuleData, "rule.btm")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
@ -204,6 +155,64 @@ func (j jvmAttack) Recover(exp core.Experiment, env Environment) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func generateRuleData(attack *core.JVMCommand) (string, error) {
|
||||||
|
bytemanTemplateSpec := core.BytemanTemplateSpec{
|
||||||
|
Name: attack.Name,
|
||||||
|
Class: attack.Class,
|
||||||
|
Method: attack.Method,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch attack.Action {
|
||||||
|
case core.JVMLatencyAction:
|
||||||
|
bytemanTemplateSpec.Do = fmt.Sprintf("Thread.sleep(%d)", attack.LatencyDuration)
|
||||||
|
case core.JVMExceptionAction:
|
||||||
|
bytemanTemplateSpec.Do = fmt.Sprintf("throw new %s", attack.ThrowException)
|
||||||
|
case core.JVMReturnAction:
|
||||||
|
bytemanTemplateSpec.Do = fmt.Sprintf("return %s", attack.ReturnValue)
|
||||||
|
case core.JVMStressAction:
|
||||||
|
bytemanTemplateSpec.Helper = core.StressHelper
|
||||||
|
bytemanTemplateSpec.Class = core.TriggerClass
|
||||||
|
bytemanTemplateSpec.Method = core.TriggerMethod
|
||||||
|
// the bind and condition is useless, only used for fill the template
|
||||||
|
bytemanTemplateSpec.Bind = "flag:boolean=true"
|
||||||
|
bytemanTemplateSpec.Condition = "true"
|
||||||
|
if attack.CPUCount > 0 {
|
||||||
|
bytemanTemplateSpec.Do = fmt.Sprintf("injectCPUStress(\"%s\", %d)", attack.Name, attack.CPUCount)
|
||||||
|
} else {
|
||||||
|
bytemanTemplateSpec.Do = fmt.Sprintf("injectMemStress(\"%s\", %s)", attack.Name, attack.MemoryType)
|
||||||
|
}
|
||||||
|
case core.JVMGCAction:
|
||||||
|
bytemanTemplateSpec.Helper = core.GCHelper
|
||||||
|
bytemanTemplateSpec.Class = core.TriggerClass
|
||||||
|
bytemanTemplateSpec.Method = core.TriggerMethod
|
||||||
|
// the bind and condition is useless, only used for fill the template
|
||||||
|
bytemanTemplateSpec.Bind = "flag:boolean=true"
|
||||||
|
bytemanTemplateSpec.Condition = "true"
|
||||||
|
bytemanTemplateSpec.Do = "gc()"
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
var t *template.Template
|
||||||
|
switch attack.Action {
|
||||||
|
case core.JVMStressAction, core.JVMGCAction:
|
||||||
|
t = template.Must(template.New("byteman rule").Parse(core.CompleteRuleTemplate))
|
||||||
|
case core.JVMExceptionAction, core.JVMLatencyAction, core.JVMReturnAction:
|
||||||
|
t = template.Must(template.New("byteman rule").Parse(core.SimpleRuleTemplate))
|
||||||
|
default:
|
||||||
|
return "", errors.Errorf("jvm action %s not supported", attack.Action)
|
||||||
|
}
|
||||||
|
if t == nil {
|
||||||
|
return "", errors.Errorf("parse byeman rule template failed")
|
||||||
|
}
|
||||||
|
err := t.Execute(buf, bytemanTemplateSpec)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("executing template", zap.Error(err))
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
func writeDataIntoFile(data string, filename string) (string, error) {
|
func writeDataIntoFile(data string, filename string) (string, error) {
|
||||||
tmpfile, err := ioutil.TempFile("", filename)
|
tmpfile, err := ioutil.TempFile("", filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright 2021 Chaos Mesh Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package chaosd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
|
||||||
|
"github.com/chaos-mesh/chaosd/pkg/core"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateRuleData(t *testing.T) {
|
||||||
|
g := NewGomegaWithT(t)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
cmd *core.JVMCommand
|
||||||
|
ruleData string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
&core.JVMCommand{
|
||||||
|
Name: "test",
|
||||||
|
JVMCommonSpec: core.JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
|
Action: core.JVMExceptionAction,
|
||||||
|
JVMClassMethodSpec: core.JVMClassMethodSpec{
|
||||||
|
Class: "testClass",
|
||||||
|
Method: "testMethod",
|
||||||
|
},
|
||||||
|
ThrowException: "java.io.IOException(\"BOOM\")",
|
||||||
|
},
|
||||||
|
"\nRULE test\nCLASS testClass\nMETHOD testMethod\nAT ENTRY\nIF true\nDO\n\tthrow new java.io.IOException(\"BOOM\");\nENDRULE\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&core.JVMCommand{
|
||||||
|
Name: "test",
|
||||||
|
JVMCommonSpec: core.JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
|
Action: core.JVMReturnAction,
|
||||||
|
JVMClassMethodSpec: core.JVMClassMethodSpec{
|
||||||
|
Class: "testClass",
|
||||||
|
Method: "testMethod",
|
||||||
|
},
|
||||||
|
ReturnValue: "\"test\"",
|
||||||
|
},
|
||||||
|
"\nRULE test\nCLASS testClass\nMETHOD testMethod\nAT ENTRY\nIF true\nDO\n\treturn \"test\";\nENDRULE\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&core.JVMCommand{
|
||||||
|
Name: "test",
|
||||||
|
JVMCommonSpec: core.JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
|
Action: core.JVMLatencyAction,
|
||||||
|
JVMClassMethodSpec: core.JVMClassMethodSpec{
|
||||||
|
Class: "testClass",
|
||||||
|
Method: "testMethod",
|
||||||
|
},
|
||||||
|
LatencyDuration: 5000,
|
||||||
|
},
|
||||||
|
"\nRULE test\nCLASS testClass\nMETHOD testMethod\nAT ENTRY\nIF true\nDO\n\tThread.sleep(5000);\nENDRULE\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&core.JVMCommand{
|
||||||
|
Name: "test",
|
||||||
|
JVMCommonSpec: core.JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
|
Action: core.JVMStressAction,
|
||||||
|
JVMStressSpec: core.JVMStressSpec{
|
||||||
|
CPUCount: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"\nRULE test\nCLASS org.chaos_mesh.chaos_agent.TriggerThread\nMETHOD triggerFunc\nHELPER org.chaos_mesh.byteman.helper.StressHelper\nAT ENTRY\nBIND flag:boolean=true;\nIF true\nDO\n\tinjectCPUStress(\"test\", 1);\nENDRULE\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&core.JVMCommand{
|
||||||
|
Name: "test",
|
||||||
|
JVMCommonSpec: core.JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
|
Action: core.JVMStressAction,
|
||||||
|
JVMStressSpec: core.JVMStressSpec{
|
||||||
|
MemoryType: "heap",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"\nRULE test\nCLASS org.chaos_mesh.chaos_agent.TriggerThread\nMETHOD triggerFunc\nHELPER org.chaos_mesh.byteman.helper.StressHelper\nAT ENTRY\nBIND flag:boolean=true;\nIF true\nDO\n\tinjectMemStress(\"test\", heap);\nENDRULE\n",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&core.JVMCommand{
|
||||||
|
Name: "test",
|
||||||
|
JVMCommonSpec: core.JVMCommonSpec{
|
||||||
|
Pid: 1234,
|
||||||
|
},
|
||||||
|
Action: core.JVMGCAction,
|
||||||
|
},
|
||||||
|
"\nRULE test\nCLASS org.chaos_mesh.chaos_agent.TriggerThread\nMETHOD triggerFunc\nHELPER org.chaos_mesh.byteman.helper.GCHelper\nAT ENTRY\nBIND flag:boolean=true;\nIF true\nDO\n\tgc();\nENDRULE\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
ruleData, err := generateRuleData(testCase.cmd)
|
||||||
|
g.Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
g.Expect(ruleData).Should(Equal(testCase.ruleData))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,15 +13,28 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
set -u
|
set -eu
|
||||||
|
|
||||||
cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||||
cd $cur
|
cd $cur
|
||||||
|
|
||||||
bin_path=../../../bin
|
bin_path=../../../bin
|
||||||
|
|
||||||
echo "download && build && run Java example program"
|
echo "download byteman example"
|
||||||
git clone https://github.com/WangXiangUSTC/byteman-example.git
|
if [[ ! (-e byteman-example) ]]; then
|
||||||
|
git clone https://github.com/WangXiangUSTC/byteman-example.git
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "download byteman && set environment variable"
|
||||||
|
byteman_dir="byteman-chaos-mesh-download-v4.0.18-0.9"
|
||||||
|
if [[ ! (-e ${byteman_dir}.tar.gz) ]]; then
|
||||||
|
curl -fsSL -o ${byteman_dir}.tar.gz https://mirrors.chaos-mesh.org/${byteman_dir}.tar.gz
|
||||||
|
tar zxvf ${byteman_dir}.tar.gz
|
||||||
|
fi
|
||||||
|
export BYTEMAN_HOME=$cur/${byteman_dir}
|
||||||
|
export PATH=$PATH:${BYTEMAN_HOME}/bin
|
||||||
|
|
||||||
|
echo "build && run Java example program helloworld"
|
||||||
cd byteman-example/example.helloworld
|
cd byteman-example/example.helloworld
|
||||||
javac HelloWorld/Main.java
|
javac HelloWorld/Main.java
|
||||||
jar cfme HelloWorld.jar Manifest.txt HelloWorld.Main HelloWorld/Main.class
|
jar cfme HelloWorld.jar Manifest.txt HelloWorld.Main HelloWorld/Main.class
|
||||||
|
|
@ -33,19 +46,14 @@ cat helloworld.log
|
||||||
# TODO: get the PID more accurately
|
# TODO: get the PID more accurately
|
||||||
pid=`pgrep -n java`
|
pid=`pgrep -n java`
|
||||||
|
|
||||||
echo "download byteman && set environment variable"
|
|
||||||
curl -fsSL -o chaosd-byteman-download.tar.gz https://mirrors.chaos-mesh.org/jvm/chaosd-byteman-download.tar.gz
|
|
||||||
tar zxvf chaosd-byteman-download.tar.gz
|
|
||||||
export BYTEMAN_HOME=$cur/chaosd-byteman-download
|
|
||||||
export PATH=$PATH:${BYTEMAN_HOME}/bin
|
|
||||||
|
|
||||||
echo "run chaosd to inject failure into JVM, and check"
|
echo "run chaosd to inject failure into JVM, and check"
|
||||||
$bin_path/chaosd attack jvm install --port 9288 --pid $pid
|
|
||||||
|
|
||||||
$bin_path/chaosd attack jvm submit return --class Main --method getnum --port 9288 --value 99999
|
$bin_path/chaosd attack jvm return --class Main --method getnum --port 9288 --value 99999 --pid $pid
|
||||||
|
sleep 1
|
||||||
check_contains "99999" helloworld.log
|
check_contains "99999" helloworld.log
|
||||||
|
|
||||||
$bin_path/chaosd attack jvm submit exception --class Main --method sayhello --port 9288 --exception 'java.io.IOException("BOOM")'
|
$bin_path/chaosd attack jvm exception --class Main --method sayhello --port 9288 --exception 'java.io.IOException("BOOM")' --pid $pid
|
||||||
|
sleep 1
|
||||||
check_contains "BOOM" helloworld.log
|
check_contains "BOOM" helloworld.log
|
||||||
|
|
||||||
# TODO: add test for latency, stress and gc
|
# TODO: add test for latency, stress and gc
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue