Skip to content

Commit 3573c34

Browse files
MandssSxcaspar
authored andcommitted
Add cri command
1 parent 3d386bd commit 3573c34

File tree

8 files changed

+179
-21
lines changed

8 files changed

+179
-21
lines changed

Makefile

+25-7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ BLADE_EXEC_OS_BRANCH=v1.3.0
4949
BLADE_EXEC_DOCKER_PROJECT=https://github.com/chaosblade-io/chaosblade-exec-docker.git
5050
BLADE_EXEC_DOCKER_BRANCH=v1.3.0
5151

52+
# chaosblade-exec-cri
53+
BLADE_EXEC_CRI_PROJECT=https://github.com/chaosblade-io/chaosblade-exec-cri.git
54+
BLADE_EXEC_CRI_BRANCH=v1.3.0
55+
5256
# chaosblade-exec-kubernetes
5357
BLADE_OPERATOR_PROJECT=https://github.com/chaosblade-io/chaosblade-operator.git
5458
BLADE_OPERATOR_BRANCH=v1.3.0
@@ -65,6 +69,10 @@ BLADE_EXEC_CPLUS_BRANCH=master
6569
DOCKER_YAML_FILE_NAME=chaosblade-docker-spec-$(BLADE_VERSION).yaml
6670
DOCKER_YAML_FILE_PATH=$(BUILD_TARGET_BIN)/$(DOCKER_YAML_FILE_NAME)
6771

72+
# cri yaml
73+
CRI_YAML_FILE_NAME=chaosblade-cri-spec-$(BLADE_VERSION).yaml
74+
CRI_YAML_FILE_PATH=$(BUILD_TARGET_BIN)/$(CRI_YAML_FILE_NAME)
75+
6876
# check yaml
6977
CHECK_YAML_FILE_NAME=chaosblade-check-spec-$(BLADE_VERSION).yaml
7078
CHECK_YANL_FILE_OSS=https://chaosblade.oss-cn-hangzhou.aliyuncs.com/agent/github/$(BLADE_VERSION)/$(CHECK_YAML_FILE_NAME)
@@ -82,24 +90,24 @@ help:
8290
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>...\033[0m\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
8391

8492
##@ Build
85-
build: pre_build cli os docker cplus java kubernetes upx package check_yaml ## Build all scenarios
93+
build: pre_build cli os docker cri cplus java kubernetes upx package check_yaml ## Build all scenarios
8694

8795
# for example: make build_with cli os_darwin
88-
build_with: pre_build ## Select scenario build, for example `make build_with cli os docker kubernetes java cplus`
96+
build_with: pre_build ## Select scenario build, for example `make build_with cli os docker cri kubernetes java cplus`
8997

9098
# for example: make build_with_linux cli os
91-
build_with_linux: pre_build build_linux_with_arg ## Select scenario build linux version by docker image, for example `make build_with_linux ARGS="cli os"`
99+
build_with_linux: pre_build build_linux_with_arg ## Select scenario build linux version by docker cri image, for example `make build_with_linux ARGS="cli os"`
92100

93-
build_with_linux_arm: pre_build build_linux_arm_with_arg ## Select scenario build linux version by docker image, for example `make build_with_linux_arm ARGS="cli os"`
101+
build_with_linux_arm: pre_build build_linux_arm_with_arg ## Select scenario build linux version by docker cri image, for example `make build_with_linux_arm ARGS="cli os"`
94102

95103
# build chaosblade linux version by docker image
96104
build_linux: ## Build linux version of all scenarios by docker image
97-
make build_with_linux ARGS="cli os docker kubernetes java cplus check_yaml" upx package
105+
make build_with_linux ARGS="cli os docker cri kubernetes java cplus check_yaml" upx package
98106

99107
build_linux_arm: ## Build linux arm version of all scenarios by docker image
100-
make build_with_linux_arm ARGS="cli os docker kubernetes java cplus check_yaml" upx package
108+
make build_with_linux_arm ARGS="cli os docker cri kubernetes java cplus check_yaml" upx package
101109

102-
build_darwin: pre_build cli os_darwin docker cplus java kubernetes upx package check_yaml ## Build all scenarios darwin version
110+
build_darwin: pre_build cli os_darwin docker cri cplus java kubernetes upx package check_yaml ## Build all scenarios darwin version
103111

104112
##@ Build sub
105113

@@ -158,6 +166,16 @@ endif
158166
cp $(BUILD_TARGET_CACHE)/chaosblade-operator/$(BUILD_TARGET_BIN)/* $(BUILD_TARGET_BIN)
159167
cp $(BUILD_TARGET_CACHE)/chaosblade-operator/$(BUILD_TARGET_YAML)/* $(BUILD_TARGET_YAML)
160168

169+
cri: ## Build cri experimental scenarios.
170+
ifneq ($(BUILD_TARGET_CACHE)/chaosblade-exec-cri, $(wildcard $(BUILD_TARGET_CACHE)/chaosblade-exec-cri))
171+
git clone -b $(BLADE_EXEC_CRI_BRANCH) $(BLADE_EXEC_CRI_PROJECT) $(BUILD_TARGET_CACHE)/chaosblade-exec-cri
172+
else
173+
git -C $(BUILD_TARGET_CACHE)/chaosblade-exec-cri pull origin $(BLADE_EXEC_CRI_BRANCH)
174+
endif
175+
make -C $(BUILD_TARGET_CACHE)/chaosblade-exec-cri
176+
cp $(BUILD_TARGET_CACHE)/chaosblade-exec-cri/$(BUILD_TARGET_YAML)/* $(BUILD_TARGET_YAML)
177+
178+
161179
java: ## Build java experimental scenarios.
162180
ifneq ($(BUILD_TARGET_CACHE)/chaosblade-exec-jvm, $(wildcard $(BUILD_TARGET_CACHE)/chaosblade-exec-jvm))
163181
git clone -b $(BLADE_EXEC_JVM_BRANCH) $(BLADE_EXEC_JVM_PROJECT) $(BUILD_TARGET_CACHE)/chaosblade-exec-jvm

README.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![logo](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/doc/image/chaosblade-logo.png)
1+
![logo](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/doc/image/chaosblade-logo.png)
22

33
# Chaosblade: An Easy to Use and Powerful Chaos Engineering Toolkit
44
[![Build Status](https://travis-ci.org/chaosblade-io/chaosblade.svg?branch=master)](https://travis-ci.org/chaosblade-io/chaosblade)
@@ -17,14 +17,15 @@ ChaosBlade is not only easy to use, but also supports rich experimental scenario
1717
* Basic resources: such as CPU, memory, network, disk, process and other experimental scenarios;
1818
* Java applications: such as databases, caches, messages, JVM itself, microservices, etc. You can also specify any class method to inject various complex experimental scenarios;
1919
* C ++ applications: such as specifying arbitrary methods or experimental lines of code injection delay, tampering with variables and return values;
20-
* Docker container: such as killing the container, the CPU in the container, memory, network, disk, process and other experimental scenarios;
20+
* container: such as killing the container, the CPU in the container, memory, network, disk, process and other experimental scenarios;
2121
* Cloud-native platforms: For example, CPU, memory, network, disk, and process experimental scenarios on Kubernetes platform nodes, Pod network and Pod itself experimental scenarios such as killing Pods, and container experimental scenarios such as the aforementioned Docker container experimental scenario;
2222

2323
Encapsulating scenes by domain into individual projects can not only standardize the scenes in the domain, but also facilitate the horizontal and vertical expansion of the scenes. By following the chaos experimental model, the chaosblade cli can be called uniformly. The items currently included are:
2424
* [chaosblade](https://github.com/chaosblade-io/chaosblade): Chaos experiment management tool, including commands for creating experiments, destroying experiments, querying experiments, preparing experimental environments, and canceling experimental environments. It is the execution of chaotic experiments. Tools, execution methods include CLI and HTTP. Provides complete commands, experimental scenarios, and scenario parameter descriptions, and the operation is simple and clear.
2525
* [chaosblade-spec-go](https://github.com/chaosblade-io/chaosblade-spec-go): Chaos experimental model Golang language definition, scenes implemented using Golang language are easy to implement based on this specification.
2626
* [chaosblade-exec-os](https://github.com/chaosblade-io/chaosblade-exec-os): Implementation of basic resource experimental scenarios.
2727
* [chaosblade-exec-docker](https://github.com/chaosblade-io/chaosblade-exec-docker): Docker container experimental scenario implementation, standardized by calling the Docker API.
28+
* [chaosblade-exec-cri](https://github.com/chaosblade-io/chaosblade-exec-cri): Container experimental scenario implementation, standardized by calling the CRI.
2829
* [chaosblade-operator](https://github.com/chaosblade-io/chaosblade-operator): Kubernetes platform experimental scenario is implemented, chaos experiments are defined by Kubernetes standard CRD method, it is very convenient to use Kubernetes resource operation method To create, update, and delete experimental scenarios, including using kubectl, client-go, etc., and also using the chaosblade cli tool described above.
2930
* [chaosblade-exec-jvm](https://github.com/chaosblade-io/chaosblade-exec-jvm): Java application experimental scenario implementation, using Java Agent technology to mount dynamically, without any access, zero-cost use It also supports uninstallation and completely recycles various resources created by the Agent.
3031
* [chaosblade-exec-cplus](https://github.com/chaosblade-io/chaosblade-exec-cplus): C ++ application experimental scenario implementation, using GDB technology to implement method and code line level experimental scenario injection.
@@ -44,8 +45,8 @@ Use the `blade help [COMMAND]` or `blade [COMMAND] -h` command to view help
4445

4546
## Experience Demo
4647
Download the chaosblade demo image and experience the use of the blade toolkit
47-
48-
![demo.gif](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/agent/release/chaosblade-demo-0.0.1.gif)
48+
49+
![demo.gif](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/agent/release/chaosblade-demo-0.0.1.gif)
4950

5051
Download image command:
5152
```shell script
@@ -83,7 +84,7 @@ ARGS="cli os" make build_with_linux
8384
```
8485

8586
## Bugs and Feedback
86-
For bug report, questions and discussions please submit [GitHub Issues](https://github.com/chaosblade-io/chaosblade/issues).
87+
For bug report, questions and discussions please submit [GitHub Issues](https://github.com/chaosblade-io/chaosblade/issues).
8788

8889
You can also contact us via:
8990
* Dingding group (recommended for chinese): 23177705

README_CN.md

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
![logo](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/doc/image/chaosblade-logo.png)
1+
![logo](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/doc/image/chaosblade-logo.png)
22

33
# ChaosBlade: 一个简单易用且功能强大的混沌实验实施工具
44
[![Build Status](https://travis-ci.org/chaosblade-io/chaosblade.svg?branch=master)](https://travis-ci.org/chaosblade-io/chaosblade)
@@ -23,6 +23,7 @@ ChaosBlade 不仅使用简单,而且支持丰富的实验场景,场景包括
2323
* [chaosblade-spec-go](https://github.com/chaosblade-io/chaosblade-spec-go): 混沌实验模型 Golang 语言定义,便于使用 Golang 语言实现的场景都基于此规范便捷实现。
2424
* [chaosblade-exec-os](https://github.com/chaosblade-io/chaosblade-exec-os): 基础资源实验场景实现。
2525
* [chaosblade-exec-docker](https://github.com/chaosblade-io/chaosblade-exec-docker): Docker 容器实验场景实现,通过调用 Docker API 标准化实现。
26+
* [chaosblade-exec-cri](https://github.com/chaosblade-io/chaosblade-exec-cri): 容器实验场景实现,通过调用 CRI 标准化实现。
2627
* [chaosblade-operator](https://github.com/chaosblade-io/chaosblade-operator): Kubernetes 平台实验场景实现,将混沌实验通过 Kubernetes 标准的 CRD 方式定义,很方便的使用 Kubernetes 资源操作的方式来创建、更新、删除实验场景,包括使用 kubectl、client-go 等方式执行,而且还可以使用上述的 chaosblade cli 工具执行。
2728
* [chaosblade-exec-jvm](https://github.com/chaosblade-io/chaosblade-exec-jvm): Java 应用实验场景实现,使用 Java Agent 技术动态挂载,无需任何接入,零成本使用,而且支持卸载,完全回收 Agent 创建的各种资源。
2829
* [chaosblade-exec-cplus](https://github.com/chaosblade-io/chaosblade-exec-cplus): C++ 应用实验场景实现,使用 GDB 技术实现方法、代码行级别的实验场景注入。
@@ -37,12 +38,12 @@ chaosblade 支持 CLI 和 HTTP 两种调用方式,支持的命令如下:
3738
* destroy:简写是 d,销毁之前的混沌实验,比如销毁上面提到的 Dubbo 延迟实验,命令是 `blade destroy UID`
3839
* status:简写 s,查询准备阶段或者实验的状态,命令是 `blade status UID` 或者 `blade status --type create`
3940
* server:启动 web server,暴露 HTTP 服务,可以通过 HTTP 请求来调用 chaosblade。例如在目标机器xxxx上执行:`blade server start -p 9526`,执行 CPU 满载实验:`curl "http:/xxxx:9526/chaosblade?cmd=create%20cpu%20fullload"`
40-
41+
4142
以上命令帮助均可使用 `blade help [COMMAND]` 或者 `blade [COMMAND] -h` 查看,也可查看[新手指南](https://github.com/chaosblade-io/chaosblade/wiki/%E6%96%B0%E6%89%8B%E6%8C%87%E5%8D%97),或者上述中文使用文档,快速上手使用。
4243

4344
## 快速体验
44-
如果想不下载 chaosblade 工具包,快速体验 chaosblade,可以拉取 docker 镜像并运行,在容器内体验。
45-
![demo.gif](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/agent/release/chaosblade-demo-0.0.1.gif)
45+
如果想不下载 chaosblade 工具包,快速体验 chaosblade,可以拉取 docker 镜像并运行,在容器内体验。
46+
![demo.gif](https://chaosblade.oss-cn-hangzhou.aliyuncs.com/agent/release/chaosblade-demo-0.0.1.gif)
4647

4748
操作步骤如下:
4849
下载镜像:
@@ -83,7 +84,7 @@ ARGS="cli os" make build_with_linux
8384
```
8485

8586
## 缺陷&建议
86-
欢迎提交缺陷、问题、建议和新功能,所有项目(包含其他子项目)的问题都可以提交到[Github Issues](https://github.com/chaosblade-io/chaosblade/issues)
87+
欢迎提交缺陷、问题、建议和新功能,所有项目(包含其他子项目)的问题都可以提交到[Github Issues](https://github.com/chaosblade-io/chaosblade/issues)
8788

8889
你也可以通过以下方式联系我们:
8990
* 钉钉群(推荐):23177705

build/spec/spec.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,18 @@ func main() {
4040
osSpecFile := path.Join(filePath, fmt.Sprintf("chaosblade-os-spec-%s.yaml", version))
4141
k8sSpecFile := path.Join(filePath, fmt.Sprintf("chaosblade-k8s-spec-%s.yaml", version))
4242
dockerSpecFile := path.Join(filePath, fmt.Sprintf("chaosblade-docker-spec-%s.yaml", version))
43+
criSpecFile := path.Join(filePath, fmt.Sprintf("chaosblade-cri-spec-%s.yaml", version))
4344
cplusSpecFile := path.Join(filePath, "chaosblade-cplus-spec.yaml")
4445
chaosSpecFile := path.Join(targetPath, "chaosblade.spec.yaml")
4546

4647
osModels := getOsModels(osSpecFile)
4748
jvmModels := getJvmModels(jvmSpecFile)
4849
cplusModels := getCplusModels(cplusSpecFile)
4950
dockerModels := getDockerModels(dockerSpecFile)
51+
criModels := getCriModels(criSpecFile)
5052
k8sModels := getKubernetesModels(k8sSpecFile)
5153

52-
models := mergeModels(osModels, jvmModels, dockerModels, k8sModels, cplusModels)
54+
models := mergeModels(osModels, jvmModels, dockerModels, cplusModels, criModels, k8sModels)
5355

5456
file, err := os.OpenFile(chaosSpecFile, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0755)
5557
if err != nil {
@@ -90,6 +92,14 @@ func getDockerModels(dockerSpecFile string) *spec.Models {
9092
return models
9193
}
9294

95+
func getCriModels(criSpecFile string) *spec.Models {
96+
models, err := util.ParseSpecsToModel(criSpecFile, nil)
97+
if err != nil {
98+
logrus.Fatalf("parse cri spec failed, %s", err)
99+
}
100+
return models
101+
}
102+
93103
func getKubernetesModels(k8sSpecFile string) *spec.Models {
94104
models, err := util.ParseSpecsToModel(k8sSpecFile, nil)
95105
if err != nil {

cli/cmd/create.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func (cc *CreateCommand) Init() {
6363
Example: createExample(),
6464
}
6565
flags := cc.command.PersistentFlags()
66-
flags.StringVar(&uid, UidFlag, "", "Set Uid for the experiment, adapt to docker")
66+
flags.StringVar(&uid, UidFlag, "", "Set Uid for the experiment, adapt to docker and cri")
6767
flags.BoolVarP(&cc.async, AsyncFlag, "a", false, "whether to create asynchronously, default is false")
6868
flags.StringVarP(&cc.endpoint, EndpointFlag, "e", "", "the create result reporting address. It takes effect only when the async value is true and the value is not empty")
6969
flags.BoolVarP(&cc.nohup, NohupFlag, "n", false, "used to internal async create, no need to config")
@@ -144,7 +144,7 @@ func (cc *CreateCommand) actionRunEFunc(target, scope string, actionCommand *act
144144
var args string
145145
if scope == "host" {
146146
args = fmt.Sprintf("create %s %s --uid %s --nohup=true", target, actionCommand.Name(), model.Uid)
147-
} else if scope == "docker" {
147+
} else if scope == "docker" || scope == "cri" {
148148
args = fmt.Sprintf("create %s %s %s --uid %s --nohup=true", scope, target, actionCommand.Name(), model.Uid)
149149
} else {
150150
args = fmt.Sprintf("create k8s %s-%s %s --uid %s --nohup=true", scope, target, actionCommand.Name(), model.Uid)

cli/cmd/exp.go

+27-1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"github.com/spf13/pflag"
3030

3131
"github.com/chaosblade-io/chaosblade/exec/cplus"
32+
"github.com/chaosblade-io/chaosblade/exec/cri"
3233
"github.com/chaosblade-io/chaosblade/exec/docker"
3334
"github.com/chaosblade-io/chaosblade/exec/jvm"
3435
"github.com/chaosblade-io/chaosblade/exec/kubernetes"
@@ -119,6 +120,8 @@ func (ec *baseExpCommandService) registerSubCommands() {
119120
ec.registerCplusExpCommands()
120121
// register docker command
121122
ec.registerDockerExpCommands()
123+
// register cri command
124+
ec.registerCriExpCommands()
122125
// register k8s command
123126
ec.registerK8sExpCommands()
124127
}
@@ -216,10 +219,32 @@ func (ec *baseExpCommandService) registerK8sExpCommands() []*modelCommand {
216219
return modelCommands
217220
}
218221

222+
// registerCriExpCommands
223+
func (ec *baseExpCommandService) registerCriExpCommands() []*modelCommand {
224+
file := path.Join(util.GetYamlHome(), fmt.Sprintf("chaosblade-cri-spec-%s.yaml", version.Ver))
225+
models, err := specutil.ParseSpecsToModel(file, cri.NewExecutor())
226+
if err != nil {
227+
return nil
228+
}
229+
criSpec := cri.NewCommandModelSpec()
230+
modelCommands := make([]*modelCommand, 0)
231+
for idx := range models.Models {
232+
model := &models.Models[idx]
233+
command := ec.registerExpCommand(model, criSpec.Name())
234+
modelCommands = append(modelCommands, command)
235+
}
236+
criCmd := ec.registerExpCommand(criSpec, "")
237+
cobraCmd := criCmd.CobraCmd()
238+
for _, child := range modelCommands {
239+
copyAndAddCommand(cobraCmd, child.command)
240+
}
241+
return modelCommands
242+
}
243+
219244
// registerExpCommand
220245
func (ec *baseExpCommandService) registerExpCommand(commandSpec spec.ExpModelCommandSpec, parentTargetCmd string) *modelCommand {
221246
cmdName := commandSpec.Name()
222-
if commandSpec.Scope() != "" && commandSpec.Scope() != "host" && commandSpec.Scope() != "docker" && commandSpec.Scope() != OperatorCommand {
247+
if commandSpec.Scope() != "" && commandSpec.Scope() != "host" && commandSpec.Scope() != "docker" && commandSpec.Scope() != "cri" && commandSpec.Scope() != OperatorCommand {
223248
cmdName = fmt.Sprintf("%s-%s", commandSpec.Scope(), commandSpec.Name())
224249
}
225250
cmd := &cobra.Command{
@@ -365,4 +390,5 @@ func copyAndAddCommand(parent, child *cobra.Command) {
365390
for _, command := range commands {
366391
copyAndAddCommand(newChild, command)
367392
}
393+
368394
}

exec/cri/executor.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 1999-2020 Alibaba Group Holding Ltd.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package cri
18+
19+
import (
20+
"context"
21+
22+
"github.com/chaosblade-io/chaosblade-exec-cri/exec"
23+
"github.com/chaosblade-io/chaosblade-spec-go/channel"
24+
"github.com/chaosblade-io/chaosblade-spec-go/spec"
25+
"github.com/chaosblade-io/chaosblade-spec-go/util"
26+
)
27+
28+
type Executor struct {
29+
executors map[string]spec.Executor
30+
}
31+
32+
func NewExecutor() spec.Executor {
33+
return &Executor{
34+
executors: exec.GetAllExecutors(),
35+
}
36+
}
37+
38+
func (*Executor) Name() string {
39+
return "cri"
40+
}
41+
42+
func (e *Executor) Exec(uid string, ctx context.Context, model *spec.ExpModel) *spec.Response {
43+
key := exec.GetExecutorKey(model.Target, model.ActionName)
44+
executor := e.executors[key]
45+
if executor == nil {
46+
util.Errorf(uid, util.GetRunFuncName(), spec.CriExecNotFound.Sprintf(key))
47+
return spec.ResponseFailWithFlags(spec.CriExecNotFound, key)
48+
}
49+
executor.SetChannel(channel.NewLocalChannel())
50+
return executor.Exec(uid, ctx, model)
51+
}
52+
53+
func (*Executor) SetChannel(channel spec.Channel) {
54+
}

0 commit comments

Comments
 (0)