├── .gitpod.Dockerfile ├── test ├── utilities │ ├── check_contains │ └── dummy.go └── integration_test │ ├── user_defined │ └── run.sh │ ├── network │ └── run.sh │ ├── run.sh │ ├── mtls_server │ ├── gen_certs.sh │ └── run.sh │ ├── stress │ └── run.sh │ └── process │ └── run.sh ├── .gitpod.yml ├── hack ├── pause.c ├── boilerplate │ ├── boilerplate.sh.txt │ ├── boilerplate.go.txt │ └── boilerplate.generatego.txt ├── suicide.c ├── generate_swagger_spec.sh ├── verify-boilerplate.sh └── version.sh ├── images ├── chaosd │ └── Dockerfile └── build-base │ └── Dockerfile ├── .gitignore ├── pkg ├── swaggerserver │ ├── swaggerserver.go │ ├── empty_handler.go │ └── swagger_handler.go ├── core │ ├── error.go │ ├── vm.go │ ├── host.go │ ├── search.go │ ├── common_test.go │ ├── disk_test.go │ ├── user_defined.go │ ├── stress.go │ ├── process.go │ ├── experiment_run.go │ ├── common.go │ ├── redis.go │ ├── jvm_test.go │ └── clock.go ├── utils │ ├── utils.go │ ├── string.go │ ├── disk_darwin.go │ ├── path.go │ ├── command_test.go │ ├── error.go │ ├── time_test.go │ ├── env.go │ ├── tempfile.go │ ├── disk_linux.go │ ├── util.go │ ├── time.go │ ├── command.go │ ├── graph.go │ ├── cidr_test.go │ ├── cidr.go │ ├── check.go │ ├── grpc.go │ ├── pool_test.go │ ├── pool.go │ └── units.go ├── store │ ├── store.go │ ├── dbstore │ │ └── store.go │ └── experiment │ │ └── experiment_run.go ├── client │ ├── client.go │ ├── attack.go │ └── request.go ├── version │ ├── types.go │ └── version.go ├── server │ ├── chaosd │ │ ├── clock_arm64.go │ │ ├── search.go │ │ ├── host_unix.go │ │ ├── host.go │ │ ├── vm.go │ │ ├── server.go │ │ ├── user_defined.go │ │ ├── disk_test.go │ │ ├── process.go │ │ ├── recover.go │ │ ├── disk.go │ │ └── attack.go │ ├── httpserver │ │ ├── system.go │ │ └── experiment.go │ ├── utils │ │ ├── response.go │ │ ├── timeout.go │ │ └── error.go │ └── server.go ├── scheduler │ ├── store.go │ └── cron_test.go ├── crclient │ └── client.go ├── mock │ └── mock.go └── config │ └── config.go ├── .github └── workflows │ ├── ci_skip.yml │ ├── release_tag.yml │ ├── release_latest.yml │ └── ci.yml ├── docs └── placeholder.go ├── Dockerfile ├── cmd ├── server │ ├── module.go │ └── server.go ├── version │ └── version.go ├── recover │ ├── completion.go │ └── recover.go ├── attack │ ├── vm.go │ ├── attack.go │ ├── user_defined.go │ ├── clock.go │ ├── host.go │ ├── process.go │ └── stress.go ├── main.go ├── completion │ └── completion.go └── search │ └── search.go ├── ROADMAP.md ├── revive.toml ├── tools ├── file │ ├── delete.go │ ├── go.mod │ ├── file.go │ ├── rename.go │ ├── create.go │ ├── modify.go │ ├── copy.go │ ├── append.go │ └── replace.go └── PortOccupyTool.go └── README.md /.gitpod.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gitpod/workspace-full 2 | RUN sudo apt-get update && \ 3 | sudo apt-get install -y ipset stress-ng -------------------------------------------------------------------------------- /test/utilities/check_contains: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | if ! grep -Fq "$1" "$2"; then 6 | echo "TEST FAILED: $2 DOES NOT CONTAIN '$1'" 7 | echo "____________________________________" 8 | cat $2 9 | echo "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: .gitpod.Dockerfile 3 | tasks: 4 | - init: make build 5 | github: 6 | prebuilds: 7 | master: true 8 | branches: true 9 | pullRequests: true 10 | pullRequestsFromForks: true 11 | addCheck: true 12 | vscode: 13 | extensions: 14 | - golang.go 15 | - ms-azuretools.vscode-docker 16 | -------------------------------------------------------------------------------- /hack/pause.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static void handler() {} 8 | 9 | int main(int argc, char* argv[]) { 10 | signal(SIGCONT, handler); 11 | pause(); 12 | 13 | int ret = execvp(argv[1], &argv[1]); 14 | if (ret == -1) { 15 | fprintf(stderr, "%s", strerror(errno)); 16 | return -1; 17 | } 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /images/chaosd/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster-slim 2 | 3 | ARG HTTPS_PROXY 4 | ARG HTTP_PROXY 5 | 6 | ENV http_proxy $HTTP_PROXY 7 | ENV https_proxy $HTTPS_PROXY 8 | 9 | RUN apt-get update && apt-get install -y tzdata iptables ipset stress-ng iproute2 fuse util-linux && rm -rf /var/lib/apt/lists/* 10 | 11 | RUN update-alternatives --set iptables /usr/sbin/iptables-legacy 12 | 13 | ENV RUST_BACKTRACE 1 14 | 15 | COPY --from=pingcap/chaos-binary /bin/chaosd /usr/local/bin/chaosd 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | *.out.tmp 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | vendor/ 17 | 18 | .vscode/ 19 | .idea/ 20 | *.iml 21 | *.swp 22 | *.log 23 | *.fail.go 24 | .DS_Store 25 | 26 | bin/ 27 | 28 | test/integration_test/**/*.* 29 | !test/integration_test/**/*.sh 30 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.sh.txt: -------------------------------------------------------------------------------- 1 | # Copyright YEAR Chaos Mesh Authors. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # See the License for the specific language governing permissions and 12 | # limitations under the License. 13 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.go.txt: -------------------------------------------------------------------------------- 1 | // Copyright YEAR Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | -------------------------------------------------------------------------------- /hack/suicide.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char* argv[]) { 9 | // SIGTERM is sent to self to terminate current process gracefully. 10 | if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) { 11 | fprintf(stderr, "fail to SET_PDEATHSIG %s", strerror(errno)); 12 | return -1; 13 | } 14 | 15 | int ret = execvp(argv[1], &argv[1]); 16 | if (ret == -1) { 17 | fprintf(stderr, "%s", strerror(errno)); 18 | return -1; 19 | } 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /hack/boilerplate/boilerplate.generatego.txt: -------------------------------------------------------------------------------- 1 | // Copyright Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | -------------------------------------------------------------------------------- /images/build-base/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster-slim 2 | 3 | ENV DEBIAN_FRONTEND noninteractive 4 | 5 | ARG HTTPS_PROXY 6 | ARG HTTP_PROXY 7 | 8 | ENV http_proxy $HTTP_PROXY 9 | ENV https_proxy $HTTPS_PROXY 10 | 11 | RUN apt-get update && apt-get install build-essential curl git pkg-config libfuse-dev fuse -y && rm -rf /var/lib/apt/lists/* 12 | 13 | RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - 14 | RUN echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list 15 | 16 | RUN apt-get update && apt-get install yarn -y && rm -rf /var/lib/apt/lists/* 17 | -------------------------------------------------------------------------------- /pkg/swaggerserver/swaggerserver.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package swaggerserver 15 | -------------------------------------------------------------------------------- /.github/workflows/ci_skip.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | - release-* 7 | paths-ignore: 8 | - .github/workflows/ci.yml 9 | - Makefile 10 | - go.* 11 | - "**.go" 12 | 13 | jobs: 14 | pull: 15 | strategy: 16 | matrix: 17 | arch: [amd64, arm64] 18 | job: 19 | - verify 20 | - build 21 | - unit-test 22 | - integration-test 23 | runs-on: ${{ fromJson('{"amd64":"ubuntu-latest", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} 24 | 25 | steps: 26 | - run: echo "Not required to run pull jobs." 27 | -------------------------------------------------------------------------------- /docs/placeholder.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // This file only ensures `doc` package exist even if swagger is not enabled. This is required for `go mod tidy`. 15 | 16 | package docs 17 | -------------------------------------------------------------------------------- /test/utilities/dummy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | "time" 20 | ) 21 | 22 | func main() { 23 | fmt.Println(os.Getpid()) 24 | time.Sleep(time.Hour) 25 | } 26 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:experimental 2 | 3 | FROM pingcap/chaos-build-base AS go_build 4 | 5 | RUN curl https://dl.google.com/go/go1.14.6.linux-amd64.tar.gz | tar -xz -C /usr/local 6 | ENV PATH "/usr/local/go/bin:${PATH}" 7 | ENV GO111MODULE=on 8 | 9 | ARG HTTPS_PROXY 10 | ARG HTTP_PROXY 11 | 12 | RUN if [[ -n "$HTTP_PROXY" ]]; then yarn config set proxy $HTTP_PROXY; fi 13 | 14 | WORKDIR /src 15 | 16 | COPY . /src 17 | 18 | ARG UI 19 | ARG SWAGGER 20 | ARG LDFLAGS 21 | 22 | RUN --mount=type=cache,target=/root/go/pkg \ 23 | --mount=type=cache,target=/root/.cache/go-build \ 24 | --mount=type=cache,target=/src/ui/node_modules \ 25 | IMG_LDFLAGS=$LDFLAGS make binary 26 | 27 | FROM alpine:3.12 28 | 29 | RUN apk add --no-cache curl tar 30 | 31 | WORKDIR /bin 32 | 33 | COPY --from=go_build /src/bin /bin 34 | -------------------------------------------------------------------------------- /pkg/core/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import "github.com/joomcode/errorx" 17 | 18 | var ( 19 | ErrNs = errorx.NewNamespace("error.core") 20 | ErrAttackConfigValidation = ErrNs.NewType("attack_config_validation_error") 21 | ErrNonRecoverableAttack = ErrNs.NewType("non_recoverable_attack") 22 | ) 23 | -------------------------------------------------------------------------------- /pkg/utils/utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "go.uber.org/fx" 18 | ) 19 | 20 | var PrintFxLog bool 21 | 22 | // FxNewAppWithoutLog returns fx App without log 23 | func FxNewAppWithoutLog(opts ...fx.Option) *fx.App { 24 | if !PrintFxLog { 25 | opts = append(opts, fx.NopLogger) 26 | } 27 | return fx.New(opts...) 28 | } 29 | -------------------------------------------------------------------------------- /pkg/utils/string.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | func RemoveDuplicateElement(languages []string) []string { 17 | result := make([]string, 0, len(languages)) 18 | temp := map[string]struct{}{} 19 | for _, item := range languages { 20 | if _, ok := temp[item]; !ok { 21 | temp[item] = struct{}{} 22 | result = append(result, item) 23 | } 24 | } 25 | return result 26 | } 27 | -------------------------------------------------------------------------------- /cmd/server/module.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package server 15 | 16 | import ( 17 | "go.uber.org/fx" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/config" 20 | "github.com/chaos-mesh/chaosd/pkg/server" 21 | "github.com/chaos-mesh/chaosd/pkg/store" 22 | ) 23 | 24 | var Module = fx.Options( 25 | fx.Provide( 26 | func() *config.Config { 27 | return &conf 28 | }, 29 | ), 30 | store.Module, 31 | server.Module, 32 | ) 33 | -------------------------------------------------------------------------------- /pkg/swaggerserver/empty_handler.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | //go:build !swagger_server 15 | // +build !swagger_server 16 | 17 | package swaggerserver 18 | 19 | import ( 20 | "net/http" 21 | 22 | "github.com/gin-gonic/gin" 23 | ) 24 | 25 | // Handler returns an empty `http.Handler`. 26 | func Handler() gin.HandlerFunc { 27 | return func(c *gin.Context) { 28 | c.String(http.StatusOK, "Swagger UI is not built. Please run `SWAGGER=1 make`.") 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /cmd/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package version 15 | 16 | import ( 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/version" 20 | ) 21 | 22 | func NewVersionCommand() *cobra.Command { 23 | return &cobra.Command{ 24 | Use: "version", 25 | Short: "Prints the version of chaosd", 26 | Run: versionCommandFunc, 27 | } 28 | } 29 | 30 | func versionCommandFunc(cmd *cobra.Command, args []string) { 31 | version.PrintVersionInfo("Chaosd") 32 | } 33 | -------------------------------------------------------------------------------- /pkg/store/store.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package store 15 | 16 | import ( 17 | "go.uber.org/fx" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/store/dbstore" 20 | "github.com/chaos-mesh/chaosd/pkg/store/experiment" 21 | "github.com/chaos-mesh/chaosd/pkg/store/network" 22 | ) 23 | 24 | var Module = fx.Options( 25 | fx.Provide( 26 | dbstore.NewDBStore, 27 | experiment.NewStore, 28 | experiment.NewRunStore, 29 | network.NewIPSetRuleStore, 30 | network.NewIptablesRuleStore, 31 | network.NewTCRuleStore, 32 | ), 33 | ) 34 | -------------------------------------------------------------------------------- /pkg/client/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package client 15 | 16 | import ( 17 | "net/http" 18 | ) 19 | 20 | // Client is used to communicate with the chaosd 21 | type Client struct { 22 | cfg Config 23 | client *http.Client 24 | } 25 | 26 | // Config defines for chaosd client 27 | type Config struct { 28 | Addr string 29 | } 30 | 31 | // NewClient creates a new chaosd client from a given address 32 | func NewClient(cfg Config) *Client { 33 | return &Client{ 34 | cfg: cfg, 35 | client: http.DefaultClient, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /pkg/version/types.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package version 15 | 16 | // Info contains versioning information. 17 | type Info struct { 18 | GitVersion string `json:"gitVersion"` 19 | GitCommit string `json:"gitCommit"` 20 | BuildDate string `json:"buildDate"` 21 | GoVersion string `json:"goVersion"` 22 | Compiler string `json:"compiler"` 23 | Platform string `json:"platform"` 24 | } 25 | 26 | // String returns info as a human-friendly version string. 27 | func (info Info) String() string { 28 | return info.GitVersion 29 | } 30 | -------------------------------------------------------------------------------- /pkg/server/chaosd/clock_arm64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/core" 20 | ) 21 | 22 | type clockAttack struct{} 23 | 24 | var ClockAttack AttackType = clockAttack{} 25 | 26 | func (c clockAttack) Attack(options core.AttackConfig, env Environment) error { 27 | return fmt.Errorf("clock attack not supported") 28 | 29 | } 30 | 31 | func (c clockAttack) Recover(exp core.Experiment, env Environment) error { 32 | return fmt.Errorf("clock recover not supported") 33 | } 34 | -------------------------------------------------------------------------------- /pkg/server/httpserver/system.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package httpserver 15 | 16 | import ( 17 | "net/http" 18 | 19 | "github.com/gin-gonic/gin" 20 | 21 | "github.com/chaos-mesh/chaosd/pkg/version" 22 | ) 23 | 24 | type healthInfo struct { 25 | Status int `json:"status"` 26 | Message string `json:"message"` 27 | } 28 | 29 | func (s *HttpServer) healthcheck(c *gin.Context) { 30 | c.JSON(http.StatusOK, healthInfo{Status: 0}) 31 | } 32 | 33 | func (s *HttpServer) version(c *gin.Context) { 34 | c.JSON(http.StatusOK, version.Get()) 35 | } 36 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Chaosd Roadmap 2 | 3 | This document defines the roadmap for Chaosd development. 4 | 5 | ## v2.0 6 | 7 | - [ ] Support HTTP attack to simulate HTTP faults, such as abort connection, delay, etc. 8 | - [ ] Support IO attack to simulate file system faults, such as IO delay and read/write errors. 9 | - [x] Support workflow to manage a group of chaos experiments. 10 | - [x] Support use Dashboard to manage chaos experiments. 11 | - [x] Support time skew. 12 | - [ ] JVM Attack supports fault injection for applications including MySQL, PostgreSQL, RoketMQ, etc. 13 | - [ ] Support file attack, including deleting files, appending data to files, renaming files, modifying files' privilege. 14 | - [ ] Support inject faults into Kafka, including high payload, the message queue is full, unable to write into, etc. 15 | - [ ] Support inject faults into Zookeeper, including fail to receive publisher's message, fail to update config, fail to notify the update, etc. 16 | - [ ] Support inject faults into Redis, including switch primary and secondary, cache hotspot, the sentinel is unavailable, sentinel restart, etc. -------------------------------------------------------------------------------- /pkg/swaggerserver/swagger_handler.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | //go:build swagger_server 15 | // +build swagger_server 16 | 17 | package swaggerserver 18 | 19 | import ( 20 | "github.com/gin-gonic/gin" 21 | swaggerFiles "github.com/swaggo/files" 22 | ginSwagger "github.com/swaggo/gin-swagger" 23 | 24 | _ "github.com/chaos-mesh/chaosd/docs" // for swagger api 25 | ) 26 | 27 | // Handler returns a swagger `http.Handler`. 28 | func Handler() gin.HandlerFunc { 29 | return ginSwagger.WrapHandler( 30 | swaggerFiles.Handler, 31 | ginSwagger.URL("./doc.json"), 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /pkg/server/utils/response.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | type Response struct { 17 | Status int `json:"status"` 18 | Message string `json:"message"` 19 | UID string `json:"uid"` 20 | } 21 | 22 | func AttackSuccessResponse(uid string) *Response { 23 | return &Response{ 24 | Status: 200, 25 | Message: "attack successfully", 26 | UID: uid, 27 | } 28 | } 29 | 30 | func RecoverSuccessResponse(uid string) *Response { 31 | return &Response{ 32 | Status: 200, 33 | Message: "attack recover successfully", 34 | UID: uid, 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /test/integration_test/user_defined/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2022 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -u 17 | 18 | cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 19 | cd $cur 20 | 21 | bin_path=../../../bin 22 | 23 | # test user defined attack 24 | ${bin_path}/chaosd attack user-defined --attack-cmd "touch /tmp/chaos" --recover-cmd "rm /tmp/chaos" --uid 1234567890 25 | 26 | if [ ! -e /tmp/chaos ]; then 27 | echo "file not exist" 28 | exit 1 29 | fi 30 | 31 | ${bin_path}/chaosd recover 1234567890 32 | 33 | if [ -e /tmp/chaos ]; then 34 | echo "file still exist" 35 | exit 1 36 | fi 37 | 38 | exit 0 39 | -------------------------------------------------------------------------------- /pkg/core/vm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "encoding/json" 18 | ) 19 | 20 | const ( 21 | VMAction = "vm" 22 | ) 23 | 24 | type VMOption struct { 25 | CommonAttackConfig 26 | 27 | VMName string `json:"vm-name,omitempty"` 28 | } 29 | 30 | func NewVMOption() *VMOption { 31 | return &VMOption{ 32 | CommonAttackConfig: CommonAttackConfig{ 33 | Kind: VMAction, 34 | }, 35 | } 36 | } 37 | 38 | func (opt *VMOption) CompleteDefaults() { 39 | return 40 | } 41 | 42 | func (opt VMOption) RecoverData() string { 43 | data, _ := json.Marshal(opt) 44 | 45 | return string(data) 46 | } 47 | -------------------------------------------------------------------------------- /pkg/utils/disk_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "syscall" 18 | ) 19 | 20 | // GetDiskTotalSize returns the total bytes in disk 21 | func GetDiskTotalSize(path string) (total uint64, err error) { 22 | s := syscall.Statfs_t{} 23 | err = syscall.Statfs(path, &s) 24 | if err != nil { 25 | return 0, err 26 | } 27 | reservedBlocks := s.Bfree - uint64(s.Bavail) 28 | total = uint64(s.Bsize) * (s.Blocks - reservedBlocks) 29 | return total, err 30 | } 31 | 32 | func GetRootDevice() (string, error) { 33 | // TODO: complete get device of root on darwin 34 | return "", nil 35 | } 36 | -------------------------------------------------------------------------------- /pkg/scheduler/store.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package scheduler 15 | 16 | import cron "github.com/robfig/cron/v3" 17 | 18 | type CronStore interface { 19 | Add(experimentId uint, cronEntryId cron.EntryID) 20 | Remove(experimentId uint) cron.EntryID 21 | } 22 | 23 | type cronStore struct { 24 | entry map[uint]cron.EntryID 25 | } 26 | 27 | func (cs *cronStore) Add(experimentId uint, cronEntryId cron.EntryID) { 28 | cs.entry[experimentId] = cronEntryId 29 | } 30 | 31 | func (cs *cronStore) Remove(experimentId uint) cron.EntryID { 32 | entryId := cs.entry[experimentId] 33 | delete(cs.entry, experimentId) 34 | return entryId 35 | } 36 | -------------------------------------------------------------------------------- /pkg/utils/path.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "os" 18 | "os/exec" 19 | "path/filepath" 20 | 21 | "go.uber.org/zap" 22 | 23 | "github.com/pingcap/log" 24 | ) 25 | 26 | // GetProgramPath returns the path of the program 27 | func GetProgramPath() string { 28 | dir, err := exec.LookPath(os.Args[0]) 29 | if err != nil { 30 | log.Fatal("can not get the process path", zap.Error(err)) 31 | } 32 | if p, err := os.Readlink(dir); err == nil { 33 | dir = p 34 | } 35 | proPath, err := filepath.Abs(filepath.Dir(dir)) 36 | if err != nil { 37 | log.Fatal("can not get the full process path", zap.Error(err)) 38 | } 39 | return proPath 40 | } 41 | -------------------------------------------------------------------------------- /pkg/utils/command_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "fmt" 18 | "testing" 19 | ) 20 | 21 | func TestCommand_Unmarshal(t *testing.T) { 22 | type dd struct { 23 | If string `dd:"if"` 24 | Of string `dd:"oflag"` 25 | Iflag string `dd:"iflag"` 26 | } 27 | dc := Command{Name: "dd"} 28 | tests := []struct { 29 | name string 30 | d dd 31 | }{ 32 | { 33 | name: "0", 34 | d: dd{ 35 | "/dev/zero", 36 | "i,2,3", 37 | "", 38 | }, 39 | }, 40 | } 41 | for _, tt := range tests { 42 | t.Run(tt.name, func(t *testing.T) { 43 | cmd := dc.Unmarshal(tt.d) 44 | fmt.Println(cmd.String()) 45 | }) 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /pkg/server/chaosd/search.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "context" 18 | 19 | "github.com/pkg/errors" 20 | 21 | "github.com/chaos-mesh/chaosd/pkg/core" 22 | ) 23 | 24 | func (s *Server) Search(conds *core.SearchCommand) ([]*core.Experiment, error) { 25 | if len(conds.UID) > 0 { 26 | exp, err := s.expStore.FindByUid(context.Background(), conds.UID) 27 | if err != nil { 28 | return nil, errors.WithStack(err) 29 | } 30 | 31 | return []*core.Experiment{exp}, nil 32 | } 33 | 34 | exps, err := s.expStore.ListByConditions(context.Background(), conds) 35 | if err != nil { 36 | return nil, errors.WithStack(err) 37 | } 38 | 39 | return exps, nil 40 | } 41 | -------------------------------------------------------------------------------- /pkg/core/host.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "encoding/json" 18 | ) 19 | 20 | const ( 21 | HostShutdownAction = "shutdown" 22 | HostRebootAction = "reboot" 23 | ) 24 | 25 | type HostCommand struct { 26 | CommonAttackConfig 27 | } 28 | 29 | var _ AttackConfig = &HostCommand{} 30 | 31 | func (h *HostCommand) Validate() error { 32 | return h.CommonAttackConfig.Validate() 33 | } 34 | 35 | func (h HostCommand) RecoverData() string { 36 | data, _ := json.Marshal(h) 37 | 38 | return string(data) 39 | } 40 | 41 | func NewHostCommand() *HostCommand { 42 | return &HostCommand{ 43 | CommonAttackConfig: CommonAttackConfig{ 44 | Kind: HostAttack, 45 | }, 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /hack/generate_swagger_spec.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # This script generates API client from the swagger annotation in the Golang server code. 17 | 18 | set -euo pipefail 19 | 20 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" 21 | PROJECT_DIR="$(dirname "$DIR")" 22 | 23 | # See https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module 24 | 25 | cd $PROJECT_DIR 26 | 27 | export GOBIN=$PROJECT_DIR/bin 28 | export PATH=$GOBIN:$PATH 29 | 30 | echo "+ Install swagger tools" 31 | go install github.com/swaggo/swag/cmd/swag 32 | 33 | echo "+ Clean up go mod" 34 | go mod tidy 35 | 36 | echo "+ Generate swagger spec" 37 | swag init -g cmd/chaosd/main.go 38 | -------------------------------------------------------------------------------- /revive.toml: -------------------------------------------------------------------------------- 1 | ignoreGeneratedHeader = false 2 | severity = "error" 3 | confidence = 0.8 4 | errorCode = 1 5 | warningCode = 0 6 | 7 | [rule.blank-imports] 8 | [rule.context-as-argument] 9 | [rule.dot-imports] 10 | [rule.error-return] 11 | [rule.error-strings] 12 | [rule.error-naming] 13 | [rule.if-return] 14 | [rule.package-comments] 15 | [rule.range] 16 | [rule.receiver-naming] 17 | [rule.indent-error-flow] 18 | [rule.empty-block] 19 | [rule.superfluous-else] 20 | [rule.modifies-parameter] 21 | 22 | # Add these once issues are fixed 23 | #[rule.var-naming] 24 | # severity = "warning" 25 | #[rule.confusing-naming] 26 | # severity = "warning" 27 | [rule.confusing-results] 28 | severity = "warning" 29 | [rule.flag-parameter] 30 | severity = "warning" 31 | #[rule.unused-parameter] 32 | # severity = "warning" 33 | 34 | # Decide whether we want these rules 35 | # [rule.exported] 36 | 37 | # Already checked by megacheck 38 | # [rule.unreachable-code] 39 | 40 | # Adding these will slow down the linter 41 | # They are already provided by megacheck 42 | # [rule.unexported-return] 43 | # [rule.time-naming] 44 | # [rule.errorf] 45 | 46 | # Adding these will slow down the linter 47 | # Not sure if they are already provided by megacheck 48 | # [rule.var-declaration] 49 | # [rule.context-keys-type] 50 | -------------------------------------------------------------------------------- /pkg/utils/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | ) 20 | 21 | // http://tldp.org/LDP/abs/html/exitcodes.html 22 | const ( 23 | ExitSuccess = iota 24 | ExitError 25 | ExitBadConnection 26 | ExitInterrupted 27 | ExitIO 28 | ExitBadArgs = 128 29 | ) 30 | 31 | // ExitWithError exits with error 32 | func ExitWithError(code int, err error) { 33 | fmt.Fprintln(os.Stderr, "Error:", err) 34 | os.Exit(code) 35 | } 36 | 37 | // NormalExit exits normally 38 | func NormalExit(msg string) { 39 | fmt.Fprintln(os.Stdout, msg) 40 | os.Exit(ExitSuccess) 41 | } 42 | 43 | // ExitWithMsg exits with error message 44 | func ExitWithMsg(code int, msg string) { 45 | fmt.Fprintln(os.Stderr, msg) 46 | os.Exit(code) 47 | } 48 | -------------------------------------------------------------------------------- /pkg/utils/time_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | . "github.com/onsi/gomega" 18 | 19 | "testing" 20 | ) 21 | 22 | func TestEncodeClkIds(t *testing.T) { 23 | g := NewGomegaWithT(t) 24 | 25 | mask, err := EncodeClkIds([]string{"CLOCK_REALTIME"}) 26 | g.Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) 27 | g.Expect(mask).Should(Equal(uint64(1))) 28 | 29 | mask, err = EncodeClkIds([]string{"CLOCK_REALTIME", "CLOCK_MONOTONIC"}) 30 | g.Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) 31 | g.Expect(mask).Should(Equal(uint64(3))) 32 | 33 | mask, err = EncodeClkIds([]string{"CLOCK_MONOTONIC"}) 34 | g.Expect(err).ShouldNot(HaveOccurred(), "error: %+v", err) 35 | g.Expect(mask).Should(Equal(uint64(2))) 36 | } 37 | -------------------------------------------------------------------------------- /pkg/server/utils/timeout.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "os/exec" 18 | "time" 19 | 20 | "github.com/pingcap/log" 21 | "go.uber.org/zap" 22 | ) 23 | 24 | func ExecWithDeadline(t <-chan time.Time, cmd *exec.Cmd) error { 25 | done := make(chan error, 1) 26 | var output []byte 27 | var err error 28 | go func() { 29 | output, err = cmd.CombinedOutput() 30 | done <- err 31 | }() 32 | 33 | select { 34 | case <-t: 35 | if err := cmd.Process.Kill(); err != nil { 36 | log.Error("failed to kill process: ", zap.Error(err)) 37 | return err 38 | } 39 | case err := <-done: 40 | if err != nil { 41 | log.Error(err.Error()+string(output), zap.Error(err)) 42 | return err 43 | } 44 | log.Info(string(output)) 45 | } 46 | return nil 47 | } 48 | -------------------------------------------------------------------------------- /pkg/utils/env.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | "path/filepath" 20 | ) 21 | 22 | func SetRuntimeEnv() error { 23 | ex, err := os.Executable() 24 | if err != nil { 25 | return err 26 | } 27 | wd := filepath.Dir(ex) 28 | 29 | _, err = os.Stat(fmt.Sprintf("%s/tools", wd)) 30 | if os.IsNotExist(err) { 31 | return err 32 | } 33 | 34 | bytemanHome := os.Getenv("BYTEMAN_HOME") 35 | if len(bytemanHome) == 0 { 36 | err = os.Setenv("BYTEMAN_HOME", fmt.Sprintf("%s/tools/byteman", wd)) 37 | if err != nil { 38 | return err 39 | } 40 | } 41 | 42 | path := os.Getenv("PATH") 43 | err = os.Setenv("PATH", fmt.Sprintf("%s/tools:%s/bin:%s", wd, bytemanHome, path)) 44 | if err != nil { 45 | return err 46 | } 47 | 48 | return nil 49 | } 50 | -------------------------------------------------------------------------------- /cmd/recover/completion.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package recover 15 | 16 | import ( 17 | "github.com/pkg/errors" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/core" 20 | "github.com/chaos-mesh/chaosd/pkg/server/chaosd" 21 | ) 22 | 23 | type completionContext struct { 24 | uids chan string 25 | err chan error 26 | } 27 | 28 | func newCompletionCtx() *completionContext { 29 | return &completionContext{ 30 | uids: make(chan string), 31 | err: make(chan error), 32 | } 33 | } 34 | 35 | func listUid(ctx *completionContext, chaos *chaosd.Server) { 36 | exps, err := chaos.Search(&core.SearchCommand{Status: core.Success}) 37 | if err != nil { 38 | ctx.err <- errors.Wrap(err, "list exp") 39 | return 40 | } 41 | 42 | for _, exp := range exps { 43 | ctx.uids <- exp.Uid 44 | } 45 | close(ctx.uids) 46 | } 47 | -------------------------------------------------------------------------------- /tools/file/delete.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "os" 18 | 19 | "github.com/pingcap/errors" 20 | "github.com/pingcap/log" 21 | "github.com/spf13/cobra" 22 | "go.uber.org/zap" 23 | ) 24 | 25 | func NewFileDeleteCommand() *cobra.Command { 26 | var fileName string 27 | 28 | cmd := &cobra.Command{ 29 | Use: "delete", 30 | Short: "delete file", 31 | 32 | Run: func(*cobra.Command, []string) { 33 | exit(deleteFile(fileName)) 34 | }, 35 | } 36 | 37 | cmd.Flags().StringVarP(&fileName, "file-name", "o", "", "the old name of the file/directory") 38 | 39 | return cmd 40 | } 41 | 42 | func deleteFile(fileName string) error { 43 | err := os.Remove(fileName) 44 | if err != nil { 45 | log.Error("delete file faild", zap.Error(err)) 46 | return errors.WithStack(err) 47 | } 48 | 49 | return nil 50 | } 51 | -------------------------------------------------------------------------------- /pkg/utils/tempfile.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "io/ioutil" 18 | 19 | "github.com/pingcap/errors" 20 | "github.com/pingcap/log" 21 | "go.uber.org/zap" 22 | ) 23 | 24 | // CreateTempFile will create a temp file in current directory. 25 | func CreateTempFile(path string) (string, error) { 26 | tempFile, err := ioutil.TempFile(path, "example") 27 | if err != nil { 28 | log.Error("unexpected err when open temp file", zap.Error(err)) 29 | return "", err 30 | } 31 | 32 | if tempFile != nil { 33 | err = tempFile.Close() 34 | if err != nil { 35 | log.Error("unexpected err when close temp file", zap.Error(err)) 36 | return "", err 37 | } 38 | } else { 39 | err := errors.Errorf("unexpected err : file get from ioutil.TempFile is nil") 40 | return "", err 41 | } 42 | return tempFile.Name(), nil 43 | } 44 | -------------------------------------------------------------------------------- /pkg/utils/disk_linux.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "syscall" 18 | 19 | "github.com/shirou/gopsutil/disk" 20 | ) 21 | 22 | // GetDiskTotalSize returns the total bytes in disk 23 | func GetDiskTotalSize(path string) (total uint64, err error) { 24 | s := syscall.Statfs_t{} 25 | err = syscall.Statfs(path, &s) 26 | if err != nil { 27 | return 0, err 28 | } 29 | reservedBlocks := s.Bfree - s.Bavail 30 | total = uint64(s.Frsize) * (s.Blocks - reservedBlocks) 31 | return total, nil 32 | } 33 | 34 | // GetRootDevice returns the device which "/" mount on. 35 | func GetRootDevice() (string, error) { 36 | mapStat, err := disk.Partitions(false) 37 | if err != nil { 38 | return "", err 39 | } 40 | for _, stat := range mapStat { 41 | if stat.Mountpoint == "/" { 42 | return stat.Device, nil 43 | } 44 | } 45 | return "", nil 46 | } 47 | -------------------------------------------------------------------------------- /pkg/scheduler/cron_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package scheduler 15 | 16 | import ( 17 | "log" 18 | "testing" 19 | "time" 20 | ) 21 | 22 | func TestScheduler_CronDurationExceeded(t *testing.T) { 23 | diffDuration, _ := time.ParseDuration("30s") 24 | startedAt := time.Now().Add(-diffDuration) 25 | log.Println(startedAt) 26 | for _, test := range []struct { 27 | name string 28 | duration time.Duration 29 | want bool 30 | }{ 31 | { 32 | name: "not exceeded", 33 | duration: diffDuration * 2, 34 | want: false, 35 | }, 36 | { 37 | name: "exceeded", 38 | duration: diffDuration / 2, 39 | want: true, 40 | }, 41 | } { 42 | t.Run(test.name, func(t *testing.T) { 43 | got := hasCronDurationExceeded(startedAt, test.duration) 44 | if got != test.want { 45 | t.Errorf("wrong result. got: %v, want: %v", got, test.want) 46 | } 47 | }) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tools/file/go.mod: -------------------------------------------------------------------------------- 1 | module file_tool 2 | 3 | go 1.17 4 | 5 | require ( 6 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 7 | github.com/pingcap/errors v0.11.0 8 | github.com/pingcap/log v0.0.0-20211215031037-e024ba4eb0ee 9 | github.com/spf13/cobra v1.3.0 10 | github.com/swaggo/swag v1.7.9 11 | ) 12 | 13 | require ( 14 | github.com/KyleBanks/depth v1.2.1 // indirect 15 | github.com/PuerkitoBio/purell v1.1.1 // indirect 16 | github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect 17 | github.com/benbjohnson/clock v1.1.0 // indirect 18 | github.com/go-openapi/jsonpointer v0.19.5 // indirect 19 | github.com/go-openapi/jsonreference v0.19.6 // indirect 20 | github.com/go-openapi/spec v0.20.4 // indirect 21 | github.com/go-openapi/swag v0.19.15 // indirect 22 | github.com/inconshreveable/mousetrap v1.0.0 // indirect 23 | github.com/josharian/intern v1.0.0 // indirect 24 | github.com/mailru/easyjson v0.7.6 // indirect 25 | github.com/spf13/pflag v1.0.5 // indirect 26 | go.uber.org/atomic v1.9.0 // indirect 27 | go.uber.org/multierr v1.7.0 // indirect 28 | go.uber.org/zap v1.21.0 // indirect 29 | golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d // indirect 30 | golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect 31 | golang.org/x/text v0.3.7 // indirect 32 | golang.org/x/tools v0.1.7 // indirect 33 | gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect 34 | gopkg.in/yaml.v2 v2.4.0 // indirect 35 | ) 36 | -------------------------------------------------------------------------------- /pkg/core/search.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "github.com/pingcap/errors" 18 | ) 19 | 20 | type SearchCommand struct { 21 | Asc bool 22 | All bool 23 | Status string 24 | Kind string 25 | Limit uint32 26 | Offset uint32 27 | UID string 28 | } 29 | 30 | func (s SearchCommand) Validate() error { 31 | if len(s.UID) > 0 { 32 | return nil 33 | } 34 | 35 | if len(s.Kind) > 0 { 36 | attack := GetAttackByKind(s.Kind) 37 | if attack == nil { 38 | return errors.Errorf("type %s not supported", s.Kind) 39 | } 40 | } 41 | 42 | if len(s.Status) > 0 { 43 | switch s.Status { 44 | case Created, Success, Error, Destroyed, Revoked: 45 | break 46 | default: 47 | return errors.Errorf("status %s not supported", s.Status) 48 | } 49 | } 50 | 51 | if len(s.Status) == 0 && len(s.Kind) == 0 && !s.All { 52 | return errors.New("UID is required") 53 | } 54 | 55 | return nil 56 | } 57 | -------------------------------------------------------------------------------- /pkg/core/common_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import "testing" 17 | 18 | func TestScheduleConfig_ParseDuration(t *testing.T) { 19 | t.Run("EmptyDurationConfig", func(t *testing.T) { 20 | cfg := SchedulerConfig{} 21 | dur, err := cfg.ScheduleDuration() 22 | if dur != nil || err != nil { 23 | t.Errorf("invalid result. duration: %v, error: %v", dur, err) 24 | } 25 | }) 26 | t.Run("CorrectDurationConfig", func(t *testing.T) { 27 | cfg := SchedulerConfig{ 28 | Duration: "15m", 29 | } 30 | dur, err := cfg.ScheduleDuration() 31 | if dur == nil || err != nil { 32 | t.Errorf("invalid result. duration: %v, error: %v", dur, err) 33 | } 34 | }) 35 | t.Run("WrongDurationConfig", func(t *testing.T) { 36 | cfg := SchedulerConfig{ 37 | Duration: "m15", 38 | } 39 | dur, err := cfg.ScheduleDuration() 40 | if err == nil { 41 | t.Errorf("invalid result. duration: %v, error: %v", dur, err) 42 | } 43 | }) 44 | } 45 | -------------------------------------------------------------------------------- /.github/workflows/release_tag.yml: -------------------------------------------------------------------------------- 1 | name: Release tag binary 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | jobs: 7 | run: 8 | name: Upload 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | arch: [amd64, arm64] 13 | runs-on: ${{ fromJson('{"amd64":"ubuntu-latest", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} 14 | container: ${{ fromJson('{"amd64":"docker.io/rockylinux:8", "arm64":"docker.io/rockylinux:8"}')[matrix.arch] }} 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | - uses: actions/setup-go@v5 20 | with: 21 | go-version: 1.20.x 22 | 23 | - name: Prepare tools 24 | run: | 25 | dnf install -y make gcc python3 26 | 27 | - name: Build binary and related tools 28 | run: make build 29 | 30 | - name: Configure awscli 31 | run: | 32 | pip3 install awscli 33 | printf "%s\n" ${{ secrets.AWS_ACCESS_KEY }} ${{ secrets.AWS_SECRET_KEY }} ${{ secrets.AWS_REGION }} "json" | aws configure 34 | 35 | - name: Upload files 36 | run: | 37 | GIT_TAG=${GITHUB_REF##*/} 38 | mv bin chaosd-${GIT_TAG}-linux-${{ matrix.arch }} 39 | tar czvf chaosd-${GIT_TAG}-linux-${{ matrix.arch }}.tar.gz chaosd-${GIT_TAG}-linux-${{ matrix.arch }} 40 | aws s3 cp chaosd-${GIT_TAG}-linux-${{ matrix.arch }}.tar.gz ${{ secrets.AWS_BUCKET_NAME }}/chaosd-${GIT_TAG}-linux-${{ matrix.arch }}.tar.gz 41 | -------------------------------------------------------------------------------- /.github/workflows/release_latest.yml: -------------------------------------------------------------------------------- 1 | name: Release latest binary 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | run: 9 | name: Upload 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | arch: [amd64, arm64] 14 | runs-on: ${{ fromJson('{"amd64":"ubuntu-latest", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} 15 | container: ${{ fromJson('{"amd64":"docker.io/rockylinux:8", "arm64":"docker.io/rockylinux:8"}')[matrix.arch] }} 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - uses: actions/setup-go@v5 21 | with: 22 | go-version: 1.20.x 23 | 24 | - name: Prepare tools 25 | run: | 26 | dnf install -y make gcc python3 27 | 28 | - name: Build binary and related tools 29 | run: make build 30 | 31 | - name: Configure awscli 32 | run: | 33 | pip3 install awscli 34 | printf "%s\n" ${{ secrets.AWS_ACCESS_KEY }} ${{ secrets.AWS_SECRET_KEY }} ${{ secrets.AWS_REGION }} "json" | aws configure 35 | 36 | # TODO: release on github package / release 37 | - name: Upload files 38 | run: | 39 | mv bin chaosd-latest-linux-${{ matrix.arch }} 40 | tar czvf chaosd-latest-linux-${{ matrix.arch }}.tar.gz chaosd-latest-linux-${{ matrix.arch }} 41 | aws s3 cp chaosd-latest-linux-${{ matrix.arch }}.tar.gz ${{ secrets.AWS_BUCKET_NAME }}/chaosd-latest-linux-${{ matrix.arch }}.tar.gz 42 | -------------------------------------------------------------------------------- /pkg/utils/util.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "math/rand" 18 | "os/exec" 19 | "time" 20 | 21 | "github.com/pingcap/log" 22 | "go.uber.org/zap" 23 | ) 24 | 25 | const charset = "abcdefghijklmnopqrstuvwxyz0123456789" 26 | 27 | func RandomStringWithCharset(length int) string { 28 | var seededRand = rand.New(rand.NewSource(time.Now().UnixNano())) 29 | b := make([]byte, length) 30 | for i := range b { 31 | b[i] = charset[seededRand.Intn(len(charset))] 32 | } 33 | return string(b) 34 | } 35 | 36 | func ExecuteCmd(cmdStr string) (string, error) { 37 | log.Info("execute cmd", zap.String("cmd", cmdStr)) 38 | cmd := exec.Command("bash", "-c", cmdStr) 39 | output, err := cmd.CombinedOutput() 40 | if err != nil { 41 | log.Error(string(output), zap.Error(err)) 42 | return "", err 43 | } 44 | if len(output) > 0 { 45 | log.Info("command output: "+string(output), zap.String("command", cmdStr)) 46 | } 47 | 48 | return string(output), nil 49 | } 50 | -------------------------------------------------------------------------------- /tools/file/file.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | 20 | _ "github.com/alecthomas/template" 21 | "github.com/spf13/cobra" 22 | _ "github.com/swaggo/swag" 23 | ) 24 | 25 | // CommandFlags are flags that used in all Commands 26 | var rootCmd = &cobra.Command{ 27 | Use: "file tool", 28 | Short: "A command line client to execute operations related to files", 29 | } 30 | 31 | func init() { 32 | rootCmd.AddCommand( 33 | NewFileOrDirCreateCommand(), 34 | NewFileOrDirRenameCommand(), 35 | NewFileModifyPrivilegeCommand(), 36 | NewFileAppendCommand(), 37 | NewFileCopyCommand(), 38 | NewFileDeleteCommand(), 39 | NewFileReplaceCommand(), 40 | ) 41 | } 42 | 43 | func main() { 44 | if err := rootCmd.Execute(); err != nil { 45 | fmt.Fprintln(os.Stderr, "Error:", err) 46 | os.Exit(1) 47 | } 48 | } 49 | 50 | func exit(err error) { 51 | if err != nil { 52 | fmt.Fprintln(os.Stderr, "Error:", err) 53 | os.Exit(1) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pkg/version/version.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package version 15 | 16 | import ( 17 | "fmt" 18 | "runtime" 19 | ) 20 | 21 | var ( 22 | gitVersion = "v0.0.0-master+$Format:%h$" 23 | gitCommit = "$Format:%H$" // sha1 from git, output of $(git rev-parse HEAD) 24 | 25 | buildDate = "1970-01-01T00:00:00Z" // build date in ISO8601 format, output of $(date -u +'%Y-%m-%dT%H:%M:%SZ') 26 | ) 27 | 28 | // PrintVersionInfo show version info to Stdout 29 | func PrintVersionInfo(name string) { 30 | fmt.Printf("%s Version: %#v\n", name, Get()) 31 | } 32 | 33 | // Get returns the overall codebase version. It's for detecting 34 | // what code a binary was built from. 35 | func Get() Info { 36 | // These variables typically come from -ldflags settings 37 | return Info{ 38 | GitVersion: gitVersion, 39 | GitCommit: gitCommit, 40 | BuildDate: buildDate, 41 | GoVersion: runtime.Version(), 42 | Compiler: runtime.Compiler, 43 | Platform: fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH), 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pkg/utils/time.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import "fmt" 17 | 18 | // EncodeClkIds will convert array of clk ids into a mask 19 | func EncodeClkIds(clkIds []string) (uint64, error) { 20 | mask := uint64(0) 21 | 22 | for _, id := range clkIds { 23 | // refer to `uapi/linux/time.h` 24 | switch id { 25 | case "CLOCK_REALTIME": 26 | mask |= 1 << 0 27 | case "CLOCK_MONOTONIC": 28 | mask |= 1 << 1 29 | case "CLOCK_PROCESS_CPUTIME_ID": 30 | mask |= 1 << 2 31 | case "CLOCK_THREAD_CPUTIME_ID": 32 | mask |= 1 << 3 33 | case "CLOCK_MONOTONIC_RAW": 34 | mask |= 1 << 4 35 | case "CLOCK_REALTIME_COARSE": 36 | mask |= 1 << 5 37 | case "CLOCK_MONOTONIC_COARSE": 38 | mask |= 1 << 6 39 | case "CLOCK_BOOTTIME": 40 | mask |= 1 << 7 41 | case "CLOCK_REALTIME_ALARM": 42 | mask |= 1 << 8 43 | case "CLOCK_BOOTTIME_ALARM": 44 | mask |= 1 << 9 45 | default: 46 | return 0, fmt.Errorf("unknown clock id %s", id) 47 | } 48 | } 49 | 50 | return mask, nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/crclient/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package crclient 15 | 16 | import ( 17 | "context" 18 | 19 | "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon/crclients" 20 | ) 21 | 22 | func NewNodeCRClient(pid int) crclients.ContainerRuntimeInfoClient { 23 | return &NodeCRClient{ 24 | Pid: uint32(pid), 25 | } 26 | } 27 | 28 | type NodeCRClient struct { 29 | Pid uint32 30 | } 31 | 32 | func (n *NodeCRClient) ListContainerIDs(_ context.Context) ([]string, error) { 33 | return nil, nil 34 | } 35 | 36 | func (n *NodeCRClient) GetLabelsFromContainerID(_ context.Context, _ string) (map[string]string, error) { 37 | return nil, nil 38 | } 39 | 40 | func (n *NodeCRClient) GetPidFromContainerID(_ context.Context, _ string) (uint32, error) { 41 | return n.Pid, nil 42 | } 43 | 44 | func (n *NodeCRClient) ContainerKillByContainerID(_ context.Context, _ string) error { 45 | return nil 46 | } 47 | 48 | func (n *NodeCRClient) FormatContainerID(_ context.Context, _ string) (string, error) { 49 | return "", nil 50 | } 51 | -------------------------------------------------------------------------------- /tools/file/rename.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "os" 18 | 19 | "github.com/pingcap/errors" 20 | "github.com/pingcap/log" 21 | "github.com/spf13/cobra" 22 | "go.uber.org/zap" 23 | ) 24 | 25 | func NewFileOrDirRenameCommand() *cobra.Command { 26 | var oldName, newName string 27 | 28 | cmd := &cobra.Command{ 29 | Use: "rename", 30 | Short: "rename file or directory", 31 | 32 | Run: func(*cobra.Command, []string) { 33 | exit(renameFileOrDir(oldName, newName)) 34 | }, 35 | } 36 | 37 | cmd.Flags().StringVarP(&oldName, "old-name", "o", "", "the old name of the file/directory") 38 | cmd.Flags().StringVarP(&newName, "new-name", "n", "", "the new name of the file/directory to be renamed") 39 | 40 | return cmd 41 | } 42 | 43 | func renameFileOrDir(oldName, newName string) error { 44 | err := os.Rename(oldName, newName) 45 | if err != nil { 46 | log.Error("rename file/dir faild", zap.Error(err)) 47 | return errors.WithStack(err) 48 | } 49 | 50 | return nil 51 | } 52 | -------------------------------------------------------------------------------- /pkg/core/disk_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "strconv" 18 | "testing" 19 | 20 | "github.com/stretchr/testify/assert" 21 | ) 22 | 23 | func Test_initSize(t *testing.T) { 24 | opt := DiskOption{ 25 | CommonAttackConfig: CommonAttackConfig{ 26 | Action: DiskFillAction, 27 | }, 28 | Size: "1024M", 29 | } 30 | byteSize, err := initSize(&opt) 31 | assert.NoError(t, err) 32 | assert.EqualValues(t, 1024<<20, byteSize) 33 | 34 | opt.Percent = "99%" 35 | opt.Size = "" 36 | byteSize, err = initSize(&opt) 37 | assert.NoError(t, err) 38 | t.Logf("percent %s with bytesize %sGB\n", opt.Percent, strconv.Itoa(int(byteSize>>30))) 39 | 40 | opt.Percent = "" 41 | opt.Size = "" 42 | _, err = initSize(&opt) 43 | assert.Error(t, err) 44 | } 45 | 46 | func Test_initPath(t *testing.T) { 47 | opt := DiskOption{ 48 | CommonAttackConfig: CommonAttackConfig{ 49 | Action: DiskFillAction, 50 | }, 51 | Path: "/1/12/1/2/1/21", 52 | } 53 | _, err := initPath(&opt) 54 | assert.Error(t, err) 55 | } 56 | -------------------------------------------------------------------------------- /pkg/server/httpserver/experiment.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package httpserver 15 | 16 | import ( 17 | "context" 18 | "net/http" 19 | 20 | "github.com/gin-gonic/gin" 21 | 22 | "github.com/chaos-mesh/chaosd/pkg/core" 23 | ) 24 | 25 | func (s *HttpServer) listExperiments(c *gin.Context) { 26 | mode, ok := c.GetQuery("launch_mode") 27 | var chaosList []*core.Experiment 28 | var err error 29 | if ok { 30 | chaosList, err = s.exp.ListByLaunchMode(context.Background(), mode) 31 | } else { 32 | chaosList, err = s.exp.List(context.Background()) 33 | } 34 | if err != nil { 35 | _ = c.AbortWithError(http.StatusInternalServerError, err) 36 | return 37 | } 38 | c.JSON(http.StatusOK, chaosList) 39 | } 40 | 41 | func (s *HttpServer) listExperimentRuns(c *gin.Context) { 42 | uid := c.Param("uid") 43 | runsList, err := s.chaos.ExpRun.ListByExperimentUID(context.Background(), uid) 44 | if err != nil { 45 | _ = c.AbortWithError(http.StatusInternalServerError, err) 46 | return 47 | } 48 | c.JSON(http.StatusOK, runsList) 49 | } 50 | -------------------------------------------------------------------------------- /pkg/server/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package server 15 | 16 | import ( 17 | "os" 18 | 19 | "github.com/go-logr/logr" 20 | "github.com/go-logr/zapr" 21 | "github.com/prometheus/client_golang/prometheus" 22 | "go.uber.org/zap" 23 | 24 | "go.uber.org/fx" 25 | 26 | "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon" 27 | 28 | "github.com/chaos-mesh/chaosd/pkg/crclient" 29 | "github.com/chaos-mesh/chaosd/pkg/scheduler" 30 | "github.com/chaos-mesh/chaosd/pkg/server/chaosd" 31 | "github.com/chaos-mesh/chaosd/pkg/server/httpserver" 32 | ) 33 | 34 | var Module = fx.Options( 35 | fx.Provide( 36 | provideNIl, 37 | chaosd.NewServer, 38 | httpserver.NewServer, 39 | crclient.NewNodeCRClient, 40 | os.Getpid, 41 | chaosdaemon.NewDaemonServerWithCRClient, 42 | scheduler.NewScheduler, 43 | ), 44 | ) 45 | 46 | func provideNIl() (prometheus.Registerer, logr.Logger) { 47 | zapLogger, err := zap.NewDevelopment() 48 | if err != nil { 49 | panic(err) 50 | } 51 | logger := zapr.NewLogger(zapLogger) 52 | return nil, logger 53 | } 54 | -------------------------------------------------------------------------------- /pkg/server/chaosd/host_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || nacl || netbsd || openbsd || solaris 15 | // +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris 16 | 17 | package chaosd 18 | 19 | import ( 20 | "os/exec" 21 | 22 | "github.com/pingcap/log" 23 | "go.uber.org/zap" 24 | ) 25 | 26 | type UnixHost struct{} 27 | 28 | var Host HostManager = UnixHost{} 29 | 30 | const CmdShutdown = "shutdown" 31 | 32 | const CmdReboot = "reboot" 33 | 34 | func (h UnixHost) Name() string { 35 | return "unix" 36 | } 37 | 38 | func (h UnixHost) Shutdown() error { 39 | cmd := exec.Command(CmdShutdown) 40 | output, err := cmd.CombinedOutput() 41 | if err != nil { 42 | log.Error(string(output), zap.Error(err)) 43 | } 44 | return err 45 | } 46 | 47 | func (h UnixHost) Reboot() error { 48 | cmd := exec.Command(CmdReboot) 49 | output, err := cmd.CombinedOutput() 50 | if err != nil { 51 | log.Error(string(output), zap.Error(err)) 52 | } 53 | return err 54 | } 55 | -------------------------------------------------------------------------------- /test/integration_test/network/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2022 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -u 17 | 18 | cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 19 | cd $cur 20 | 21 | bin_path=../../../bin 22 | 23 | # test nic down 24 | nic=$(cat /proc/net/dev | awk '{i++; if(i>2){print $1}}' | sed 's/^[\t]*//g' | sed 's/[:]*$//g' | head -n 1) 25 | 26 | ifconfig ${nic}:0 192.168.10.28 up 27 | 28 | test_nic=$(ifconfig | grep ${nic}:0 | sed 's/:0:.*/:0/g') 29 | if [[ test_nic == "" ]]; then 30 | echo "create test nic failed" 31 | exit 1 32 | fi 33 | 34 | ${bin_path}/chaosd attack network down -d ${test_nic} --duration 1s 35 | stat=$(ifconfig | grep ${test_nic} | sed 's/:0:.*/:0/g') 36 | 37 | if [[ -n ${stat} ]]; then 38 | echo "fail to disable the test nic" 39 | ifconfig ${test_nic} down 40 | exit 1 41 | fi 42 | 43 | sleep 1s 44 | 45 | stat=$(ifconfig | grep ${test_nic} | sed 's/:0:.*/:0/g') 46 | if [[ ${stat} != ${test_nic} ]]; then 47 | echo "fail to enable the test nic" 48 | exit 1 49 | fi 50 | 51 | ifconfig ${test_nic} down 52 | 53 | exit 0 -------------------------------------------------------------------------------- /pkg/utils/command.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "context" 18 | "fmt" 19 | "os/exec" 20 | "reflect" 21 | ) 22 | 23 | type Command struct { 24 | Name string 25 | } 26 | 27 | func (c Command) Unmarshal(val interface{}) *exec.Cmd { 28 | name, args := c.GetCmdArgs(val) 29 | return exec.Command(name, args...) 30 | } 31 | 32 | func (c Command) UnmarshalWithCtx(ctx context.Context, val interface{}) *exec.Cmd { 33 | name, args := c.GetCmdArgs(val) 34 | return exec.CommandContext(ctx, name, args...) 35 | } 36 | 37 | func (c Command) GetCmdArgs(val interface{}) (string, []string) { 38 | v := reflect.ValueOf(val) 39 | 40 | var options []string 41 | for i := 0; i < v.NumField(); i++ { 42 | tag := v.Type().Field(i).Tag.Get(c.Name) 43 | if v.Field(i).String() == "" || tag == "" { 44 | continue 45 | } 46 | 47 | if tag == "-" { 48 | options = append(options, v.Field(i).String()) 49 | } else { 50 | options = append(options, fmt.Sprintf("%s=%v", tag, v.Field(i).String())) 51 | } 52 | } 53 | return c.Name, options 54 | } 55 | -------------------------------------------------------------------------------- /pkg/core/user_defined.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "encoding/json" 18 | 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | var _ AttackConfig = &UserDefinedOption{} 23 | 24 | type UserDefinedOption struct { 25 | CommonAttackConfig 26 | 27 | AttackCmd string `json:"attackCmd,omitempty"` 28 | RecoverCmd string `json:"recoverCmd,omitempty"` 29 | } 30 | 31 | func (u *UserDefinedOption) Validate() error { 32 | if err := u.CommonAttackConfig.Validate(); err != nil { 33 | return err 34 | } 35 | if len(u.AttackCmd) == 0 { 36 | return errors.New("attack command not provided") 37 | } 38 | 39 | if len(u.RecoverCmd) == 0 { 40 | return errors.New("recover command not provided") 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func (u *UserDefinedOption) RecoverData() string { 47 | data, _ := json.Marshal(u) 48 | 49 | return string(data) 50 | } 51 | 52 | func NewUserDefinedOption() *UserDefinedOption { 53 | return &UserDefinedOption{ 54 | CommonAttackConfig: CommonAttackConfig{ 55 | Kind: UserDefinedAttack, 56 | }, 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /pkg/server/chaosd/host.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "github.com/pingcap/errors" 18 | perr "github.com/pkg/errors" 19 | 20 | "github.com/chaos-mesh/chaosd/pkg/core" 21 | ) 22 | 23 | type HostManager interface { 24 | Name() string 25 | Shutdown() error 26 | Reboot() error 27 | } 28 | 29 | type hostAttack struct{} 30 | 31 | var HostAttack AttackType = hostAttack{} 32 | 33 | func (hostAttack) Attack(options core.AttackConfig, _ Environment) error { 34 | hostOption, ok := options.(*core.HostCommand) 35 | if !ok { 36 | return errors.New("the type is not HostOption") 37 | } 38 | 39 | if hostOption.Action == core.HostShutdownAction { 40 | if err := Host.Shutdown(); err != nil { 41 | return perr.WithStack(err) 42 | } 43 | } 44 | 45 | if hostOption.Action == core.HostRebootAction { 46 | if err := Host.Reboot(); err != nil { 47 | return perr.WithStack(err) 48 | } 49 | } 50 | 51 | return nil 52 | } 53 | 54 | func (hostAttack) Recover(exp core.Experiment, _ Environment) error { 55 | return core.ErrNonRecoverableAttack.New("host attack not supported to recover") 56 | } 57 | -------------------------------------------------------------------------------- /tools/file/create.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "os" 18 | 19 | "github.com/pingcap/errors" 20 | "github.com/pingcap/log" 21 | "github.com/spf13/cobra" 22 | "go.uber.org/zap" 23 | ) 24 | 25 | func NewFileOrDirCreateCommand() *cobra.Command { 26 | var fileName, dirName string 27 | 28 | cmd := &cobra.Command{ 29 | Use: "create", 30 | Short: "create file or directory", 31 | 32 | Run: func(*cobra.Command, []string) { 33 | exit(createFileOrDir(fileName, dirName)) 34 | }, 35 | } 36 | 37 | cmd.Flags().StringVarP(&fileName, "file-name", "f", "", "the name of created file") 38 | cmd.Flags().StringVarP(&dirName, "dir-name", "d", "", "the name of created directory") 39 | 40 | return cmd 41 | } 42 | 43 | func createFileOrDir(fileName, dirName string) error { 44 | var err error 45 | if len(fileName) > 0 { 46 | _, err = os.Create(fileName) 47 | } else if len(dirName) > 0 { 48 | err = os.Mkdir(dirName, os.ModePerm) 49 | } 50 | 51 | if err != nil { 52 | log.Error("create file/directory failed", zap.Error(err)) 53 | return errors.WithStack(err) 54 | } 55 | 56 | return nil 57 | } 58 | -------------------------------------------------------------------------------- /test/integration_test/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eu 17 | 18 | pwd=`pwd` 19 | test_dir=test/integration_test 20 | 21 | function run() { 22 | script=$1 23 | echo "Running test $script..." 24 | TEST_NAME="$(basename "$(dirname "$script")")" \ 25 | PATH="$pwd/$test_dir/../utilities:$PATH" \ 26 | bash +x "$script" 27 | } 28 | 29 | if [ "$#" -ge 1 ]; then 30 | test_case=$1 31 | if [ "$test_case" != "*" ]; then 32 | if [ ! -d "test/integration_test/$test_case" ]; then 33 | echo $test_case "not exist" 34 | exit 0 35 | fi 36 | fi 37 | else 38 | test_case="*" 39 | fi 40 | 41 | if [ "$test_case" == "*" ]; then 42 | for script in $test_dir/$test_case/run.sh; do 43 | # stress are not supported in aarch64 44 | # TODO: support stress in aarch64, and remove this check 45 | if [[ $script == *"stress"* && "$(uname -m)" == "aarch64" ]]; then 46 | continue 47 | fi 48 | 49 | run $script 50 | done 51 | else 52 | for name in $test_case; do 53 | script="$test_dir/$name/run.sh" 54 | echo "run $script" 55 | run $script 56 | done 57 | fi -------------------------------------------------------------------------------- /pkg/client/attack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package client 15 | 16 | import ( 17 | "encoding/json" 18 | "fmt" 19 | "net/http" 20 | 21 | "github.com/pingcap/errors" 22 | 23 | "github.com/chaos-mesh/chaosd/pkg/core" 24 | "github.com/chaos-mesh/chaosd/pkg/server/utils" 25 | ) 26 | 27 | const ( 28 | processAttack = "api/attack/process" 29 | ) 30 | 31 | func (c *Client) CreateProcessAttack(attack *core.ProcessCommand) (*utils.Response, *utils.APIError, error) { 32 | a, err := json.Marshal(attack) 33 | if err != nil { 34 | return nil, nil, errors.WithStack(err) 35 | } 36 | 37 | url := fmt.Sprintf("%s/%s", c.cfg.Addr, processAttack) 38 | data, apiErr, err := doRequest(c.client, url, http.MethodPost, withJsonBody(a)) 39 | if err != nil { 40 | return nil, nil, errors.WithStack(err) 41 | } 42 | 43 | if apiErr != nil { 44 | aerr := &utils.APIError{} 45 | if err := json.Unmarshal(apiErr, aerr); err != nil { 46 | return nil, nil, errors.WithStack(err) 47 | } 48 | return nil, aerr, nil 49 | } 50 | 51 | resp := &utils.Response{} 52 | if err := json.Unmarshal(data, resp); err != nil { 53 | return nil, nil, errors.WithStack(err) 54 | } 55 | 56 | return resp, nil, nil 57 | } 58 | -------------------------------------------------------------------------------- /tools/file/modify.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "os/exec" 19 | 20 | "github.com/pingcap/errors" 21 | "github.com/pingcap/log" 22 | "github.com/spf13/cobra" 23 | "go.uber.org/zap" 24 | ) 25 | 26 | func NewFileModifyPrivilegeCommand() *cobra.Command { 27 | var fileName string 28 | var privilege uint32 29 | 30 | cmd := &cobra.Command{ 31 | Use: "modify", 32 | Short: "modify file's privilege", 33 | 34 | Run: func(*cobra.Command, []string) { 35 | exit(modifyFilePrivilege(fileName, privilege)) 36 | }, 37 | } 38 | 39 | cmd.Flags().StringVarP(&fileName, "file-name", "f", "", "the name of the file") 40 | cmd.Flags().Uint32VarP(&privilege, "privilege", "p", 0, "the privilege of the file to be changed to, for example 777") 41 | 42 | return cmd 43 | } 44 | 45 | func modifyFilePrivilege(fileName string, privilege uint32) error { 46 | cmdStr := fmt.Sprintf("chmod %d %s", privilege, fileName) 47 | cmd := exec.Command("bash", "-c", cmdStr) 48 | output, err := cmd.CombinedOutput() 49 | if err != nil { 50 | log.Error(string(output), zap.Error(err)) 51 | return errors.WithStack(err) 52 | } 53 | if len(output) > 0 { 54 | log.Info(string(output)) 55 | } 56 | 57 | return nil 58 | } 59 | -------------------------------------------------------------------------------- /pkg/core/stress.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "encoding/json" 18 | 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | const ( 23 | StressCPUAction = "cpu" 24 | StressMemAction = "mem" 25 | ) 26 | 27 | type StressCommand struct { 28 | CommonAttackConfig 29 | 30 | Load int `json:"load,omitempty"` 31 | Workers int `json:"workers,omitempty"` 32 | Size string `json:"size,omitempty"` 33 | Options []string `json:"options,omitempty"` 34 | StressngPid int32 `json:"stress-ng-pid,omitempty"` 35 | } 36 | 37 | var _ AttackConfig = &StressCommand{} 38 | 39 | func (s *StressCommand) Validate() error { 40 | if err := s.CommonAttackConfig.Validate(); err != nil { 41 | return err 42 | } 43 | if len(s.Action) == 0 { 44 | return errors.New("action not provided") 45 | } 46 | 47 | return nil 48 | } 49 | 50 | func (s *StressCommand) CompleteDefaults() { 51 | if s.Workers == 0 { 52 | s.Workers = 1 53 | } 54 | } 55 | 56 | func (s StressCommand) RecoverData() string { 57 | data, _ := json.Marshal(s) 58 | 59 | return string(data) 60 | } 61 | 62 | func NewStressCommand() *StressCommand { 63 | return &StressCommand{ 64 | CommonAttackConfig: CommonAttackConfig{ 65 | Kind: StressAttack, 66 | }, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tools/file/copy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "io" 19 | "os" 20 | 21 | "github.com/spf13/cobra" 22 | ) 23 | 24 | func NewFileCopyCommand() *cobra.Command { 25 | var fileName, copyFileName string 26 | 27 | cmd := &cobra.Command{ 28 | Use: "copy", 29 | Short: "copy file", 30 | 31 | Run: func(*cobra.Command, []string) { 32 | exit(copyFile(fileName, copyFileName)) 33 | 34 | }, 35 | } 36 | 37 | cmd.Flags().StringVarP(&fileName, "file-name", "f", "", "the name of the file to be copied") 38 | cmd.Flags().StringVarP(©FileName, "copy-file-name", "c", "", "the name of the file to be copied to") 39 | 40 | return cmd 41 | } 42 | 43 | func copyFile(fileName, copyFileName string) error { 44 | sourceFileStat, err := os.Stat(fileName) 45 | if err != nil { 46 | return err 47 | } 48 | 49 | if !sourceFileStat.Mode().IsRegular() { 50 | return fmt.Errorf("%s is not a regular file", fileName) 51 | } 52 | 53 | source, err := os.Open(fileName) 54 | if err != nil { 55 | return err 56 | } 57 | defer source.Close() 58 | 59 | destination, err := os.Create(copyFileName) 60 | if err != nil { 61 | return err 62 | } 63 | defer destination.Close() 64 | 65 | _, err = io.Copy(destination, source) 66 | return err 67 | } 68 | -------------------------------------------------------------------------------- /tools/PortOccupyTool.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "net/http" 19 | 20 | "github.com/pingcap/errors" 21 | "github.com/pingcap/log" 22 | "github.com/spf13/cobra" 23 | "go.uber.org/zap" 24 | ) 25 | 26 | func PortOccupyTool() error { 27 | var Port string 28 | var rootCmd = &cobra.Command{ 29 | Use: "http server start", 30 | Short: "http server start", 31 | Run: func(cmd *cobra.Command, args []string) { 32 | startHttp(Port) 33 | }, 34 | } 35 | 36 | rootCmd.Flags().StringVarP(&Port, "port", "p", "", "port to occupy") 37 | if err := rootCmd.Execute(); err != nil { 38 | return errors.WithStack(err) 39 | } 40 | 41 | return nil 42 | } 43 | 44 | func generateHttpPort(port string) string { 45 | s := fmt.Sprintf(":%s", port) 46 | return s 47 | } 48 | 49 | func startHttp(porttoOccupy string) { 50 | 51 | s := generateHttpPort(porttoOccupy) 52 | 53 | http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { 54 | fmt.Fprintf(w, "Hello cmd!") 55 | }) 56 | if err := http.ListenAndServe(s, nil); err != nil { 57 | log.Error("ListenAndServe", zap.Error(err)) 58 | } 59 | } 60 | 61 | func main() { 62 | if err := PortOccupyTool(); err != nil { 63 | log.Error("PortOccupyTool run fail", zap.Error(err)) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /cmd/attack/vm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package attack 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/spf13/cobra" 20 | "go.uber.org/fx" 21 | 22 | "github.com/chaos-mesh/chaosd/cmd/server" 23 | "github.com/chaos-mesh/chaosd/pkg/core" 24 | "github.com/chaos-mesh/chaosd/pkg/server/chaosd" 25 | "github.com/chaos-mesh/chaosd/pkg/utils" 26 | ) 27 | 28 | func NewVMAttackCommand(uid *string) *cobra.Command { 29 | options := core.NewVMOption() 30 | dep := fx.Options( 31 | server.Module, 32 | fx.Provide(func() *core.VMOption { 33 | options.UID = *uid 34 | return options 35 | }), 36 | ) 37 | 38 | cmd := &cobra.Command{ 39 | Use: "vm attack", 40 | Short: "vm attack by using virsh", 41 | Run: func(*cobra.Command, []string) { 42 | options.Action = core.VMAction 43 | utils.FxNewAppWithoutLog(dep, fx.Invoke(vmAttack)).Run() 44 | }, 45 | } 46 | 47 | cmd.Flags().StringVarP(&options.VMName, "vm-name", "v", "", "The name of the vm to be destoryed") 48 | return cmd 49 | } 50 | 51 | func vmAttack(options *core.VMOption, chaos *chaosd.Server) { 52 | uid, err := chaos.ExecuteAttack(chaosd.VMAttack, options, core.CommandMode) 53 | if err != nil { 54 | utils.ExitWithError(utils.ExitError, err) 55 | } 56 | 57 | utils.NormalExit(fmt.Sprintf("VM attack %v successfully, uid: %s", options, uid)) 58 | } 59 | -------------------------------------------------------------------------------- /test/integration_test/mtls_server/gen_certs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2021 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | # Generate script because certs expire in 1 year (365 days) 17 | 18 | mkdir -p client server 19 | 20 | # generate server certificate 21 | openssl req \ 22 | -x509 \ 23 | -newkey rsa:4096 \ 24 | -keyout server/server_key.pem \ 25 | -out server/server_cert.pem \ 26 | -nodes \ 27 | -days 365 \ 28 | -subj "/CN=localhost/O=Client\ Certificate\ Demo" 29 | 30 | # generate server-signed (valid) certificate 31 | openssl req \ 32 | -newkey rsa:4096 \ 33 | -keyout client/valid_key.pem \ 34 | -out client/valid_csr.pem \ 35 | -nodes \ 36 | -days 365 \ 37 | -subj "/CN=Valid" 38 | 39 | # sign with server_cert.pem 40 | openssl x509 \ 41 | -req \ 42 | -in client/valid_csr.pem \ 43 | -CA server/server_cert.pem \ 44 | -CAkey server/server_key.pem \ 45 | -out client/valid_cert.pem \ 46 | -set_serial 01 \ 47 | -days 365 48 | 49 | # generate self-signed (invalid) certificate 50 | openssl req \ 51 | -newkey rsa:4096 \ 52 | -keyout client/invalid_key.pem \ 53 | -out client/invalid_csr.pem \ 54 | -nodes \ 55 | -days 365 \ 56 | -subj "/CN=Invalid" 57 | 58 | # sign with invalid_csr.pem 59 | openssl x509 \ 60 | -req \ 61 | -in client/invalid_csr.pem \ 62 | -signkey client/invalid_key.pem \ 63 | -out client/invalid_cert.pem \ 64 | -days 365 65 | -------------------------------------------------------------------------------- /cmd/attack/attack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package attack 15 | 16 | import ( 17 | "github.com/spf13/cobra" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/core" 20 | ) 21 | 22 | func NewAttackCommand() *cobra.Command { 23 | cmd := &cobra.Command{ 24 | Use: "attack ", 25 | Short: "Attack related commands", 26 | } 27 | 28 | var uid string 29 | cmd.PersistentFlags().StringVarP(&uid, "uid", "", "", "the experiment ID") 30 | 31 | cmd.AddCommand( 32 | NewProcessAttackCommand(&uid), 33 | NewNetworkAttackCommand(&uid), 34 | NewStressAttackCommand(&uid), 35 | NewDiskAttackCommand(&uid), 36 | NewHostAttackCommand(&uid), 37 | NewJVMAttackCommand(&uid), 38 | NewClockAttackCommand(&uid), 39 | NewKafkaAttackCommand(&uid), 40 | NewRedisAttackCommand(&uid), 41 | NewFileAttackCommand(&uid), 42 | NewHTTPAttackCommand(&uid), 43 | NewVMAttackCommand(&uid), 44 | NewUserDefinedCommand(&uid), 45 | ) 46 | 47 | return cmd 48 | } 49 | 50 | func SetScheduleFlags(cmd *cobra.Command, conf *core.SchedulerConfig) { 51 | cmd.Flags().StringVar(&conf.Duration, "duration", "", 52 | `Work duration of attacks.A duration string is a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms", "1.5h" or "2h45m".Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h".`) 53 | } 54 | -------------------------------------------------------------------------------- /pkg/server/chaosd/vm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "errors" 18 | "fmt" 19 | "os/exec" 20 | 21 | "github.com/pingcap/log" 22 | "go.uber.org/zap" 23 | 24 | "github.com/chaos-mesh/chaosd/pkg/core" 25 | ) 26 | 27 | type vmAttack struct{} 28 | 29 | var VMAttack AttackType = vmAttack{} 30 | 31 | func (vm vmAttack) Attack(options core.AttackConfig, env Environment) error { 32 | vmOption, ok := options.(*core.VMOption) 33 | if !ok { 34 | return errors.New("the type is not VMOption") 35 | } 36 | 37 | cmd := exec.Command("bash", "-c", fmt.Sprintf("virsh destroy %s", vmOption.VMName)) 38 | output, err := cmd.CombinedOutput() 39 | if err != nil { 40 | log.Error(string(output), zap.Error(err)) 41 | return err 42 | } 43 | 44 | return nil 45 | } 46 | 47 | func (vmAttack) Recover(exp core.Experiment, _ Environment) error { 48 | attackConfig, err := exp.GetRequestCommand() 49 | if err != nil { 50 | return err 51 | } 52 | 53 | vmOption, ok := attackConfig.(*core.VMOption) 54 | if !ok { 55 | return errors.New("the type is not VMOption") 56 | } 57 | 58 | cmd := exec.Command("bash", "-c", fmt.Sprintf("virsh start %s", vmOption.VMName)) 59 | output, err := cmd.CombinedOutput() 60 | if err != nil { 61 | log.Error(string(output), zap.Error(err)) 62 | return err 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/server/chaosd/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "github.com/chaos-mesh/chaos-mesh/pkg/chaosdaemon" 18 | 19 | "github.com/chaos-mesh/chaosd/pkg/config" 20 | "github.com/chaos-mesh/chaosd/pkg/core" 21 | "github.com/chaos-mesh/chaosd/pkg/scheduler" 22 | "github.com/chaos-mesh/chaosd/pkg/utils" 23 | ) 24 | 25 | type Server struct { 26 | expStore core.ExperimentStore 27 | ExpRun core.ExperimentRunStore 28 | Cron scheduler.Scheduler 29 | ipsetRule core.IPSetRuleStore 30 | iptablesRule core.IptablesRuleStore 31 | tcRule core.TCRuleStore 32 | conf *config.Config 33 | svr *chaosdaemon.DaemonServer 34 | 35 | CmdPools map[string]*utils.CommandPools 36 | } 37 | 38 | func NewServer( 39 | conf *config.Config, 40 | exp core.ExperimentStore, 41 | expRun core.ExperimentRunStore, 42 | ipset core.IPSetRuleStore, 43 | iptables core.IptablesRuleStore, 44 | tc core.TCRuleStore, 45 | svr *chaosdaemon.DaemonServer, 46 | cron scheduler.Scheduler, 47 | ) *Server { 48 | return &Server{ 49 | conf: conf, 50 | expStore: exp, 51 | Cron: cron, 52 | ExpRun: expRun, 53 | ipsetRule: ipset, 54 | iptablesRule: iptables, 55 | tcRule: tc, 56 | svr: svr, 57 | CmdPools: make(map[string]*utils.CommandPools), 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tools/file/append.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "os" 19 | 20 | "github.com/pingcap/errors" 21 | "github.com/pingcap/log" 22 | "github.com/spf13/cobra" 23 | "go.uber.org/zap" 24 | ) 25 | 26 | func NewFileAppendCommand() *cobra.Command { 27 | var fileName, data string 28 | var count int 29 | 30 | cmd := &cobra.Command{ 31 | Use: "append", 32 | Short: "append data to a file", 33 | 34 | Run: func(*cobra.Command, []string) { 35 | exit(appendFile(fileName, data, count)) 36 | }, 37 | } 38 | 39 | cmd.Flags().StringVarP(&fileName, "file-name", "f", "", "append data to the file") 40 | cmd.Flags().StringVarP(&data, "data", "d", "", "the appended data") 41 | cmd.Flags().IntVarP(&count, "count", "c", 1, "the append count of data") 42 | 43 | return cmd 44 | } 45 | 46 | func appendFile(fileName, data string, count int) error { 47 | f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) 48 | if err != nil { 49 | return errors.WithStack(err) 50 | } 51 | defer func() { 52 | if err := f.Close(); err != nil { 53 | log.Error("close file failed", zap.Error(err)) 54 | } 55 | }() 56 | 57 | for i := 0; i < count; i++ { 58 | if _, err := f.Write([]byte(fmt.Sprintf("%s\n", data))); err != nil { 59 | return errors.WithStack(err) 60 | } 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/core/process.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "encoding/json" 18 | 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | const ( 23 | ProcessKillAction = "kill" 24 | ProcessStopAction = "stop" 25 | ) 26 | 27 | var _ AttackConfig = &ProcessCommand{} 28 | 29 | type ProcessCommand struct { 30 | CommonAttackConfig 31 | 32 | // Process defines the process name or the process ID. 33 | Process string `json:"process,omitempty"` 34 | Signal int `json:"signal,omitempty"` 35 | PIDs []int 36 | RecoverCmd string `json:"recoverCmd,omitempty"` 37 | // TODO: support these feature 38 | // Newest bool 39 | // Oldest bool 40 | // Exact bool 41 | // KillChildren bool 42 | // User string 43 | } 44 | 45 | func (p *ProcessCommand) Validate() error { 46 | if err := p.CommonAttackConfig.Validate(); err != nil { 47 | return err 48 | } 49 | if len(p.Process) == 0 { 50 | return errors.New("process not provided") 51 | } 52 | 53 | // TODO: validate signal 54 | 55 | return nil 56 | } 57 | 58 | func (p ProcessCommand) RecoverData() string { 59 | data, _ := json.Marshal(p) 60 | 61 | return string(data) 62 | } 63 | 64 | func NewProcessCommand() *ProcessCommand { 65 | return &ProcessCommand{ 66 | CommonAttackConfig: CommonAttackConfig{ 67 | Kind: ProcessAttack, 68 | }, 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | on: 3 | pull_request: 4 | branches: 5 | - main 6 | - release-* 7 | paths: 8 | - .github/workflows/ci.yml 9 | - Makefile 10 | - go.* 11 | - '**.go' 12 | 13 | jobs: 14 | pull: 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | arch: [amd64, arm64] 19 | job: 20 | - verify 21 | - build 22 | - unit-test 23 | - integration-test 24 | runs-on: ${{ fromJson('{"amd64":"ubuntu-latest", "arm64":["self-hosted", "Linux", "ARM64"]}')[matrix.arch] }} 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | with: 29 | ref: ${{ github.event.pull_request.head.sha }} 30 | path: go/src/github.com/${{ github.repository }} 31 | - uses: actions/setup-go@v5 32 | with: 33 | go-version: 1.20.x 34 | 35 | - name: ${{ matrix.job }} 36 | run: | 37 | # use sh function 38 | if [[ "$job" == "verify" ]]; then 39 | # preload go modules before goimports 40 | go mod download -x 41 | make check 42 | make groupimports || echo 0 43 | echo "Please make check before creating a PR" 44 | git diff --quiet -- . || (git diff | cat && false) 45 | elif [[ "$job" == "build" ]]; then 46 | make build 47 | elif [[ "$job" == "unit-test" ]]; then 48 | make unit-test 49 | elif [[ "$job" == "integration-test" ]]; then 50 | curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - 51 | sudo apt-get update 52 | sudo apt-get install -y stress-ng 53 | make integration-test 54 | else 55 | make $job 56 | fi 57 | working-directory: ${{ github.workspace }}/go/src/github.com/${{ github.repository }} 58 | env: 59 | job: ${{ matrix.job }} 60 | -------------------------------------------------------------------------------- /hack/verify-boilerplate.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -o errexit 17 | set -o nounset 18 | set -o pipefail 19 | 20 | ROOT=$(unset CDPATH && cd $(dirname "${BASH_SOURCE[0]}")/.. && pwd) 21 | cd $ROOT 22 | 23 | boiler="${ROOT}/hack/boilerplate/boilerplate.py" 24 | 25 | # ignored files is a list of files we should ignore, e.g. k8s script. 26 | # one file per line 27 | ignored_files='./hack/cherry_pick_pull.sh 28 | hack/generate-internal-groups.sh' 29 | 30 | files=($(find . -type f -not \( \ 31 | -path './hack/boilerplate/*' \ 32 | -o -path './.git/*' \ 33 | -o -path './.*/*' \ 34 | -o -path './vendor/*' \ 35 | -o -path './ui/*' \ 36 | -o -path '*/Makefile' \ 37 | -o -path '*/Dockerfile' \ 38 | -o -path './images/*' \ 39 | -o -path './pkg/uiserver/embedded_assets_handler.go' \ 40 | -o -path '*/pb/*' \ 41 | -o -path '*/*.deepcopy.go' \ 42 | -o -path '*/*pb.go' \ 43 | \) | grep -v -F "$ignored_files" 44 | )) 45 | 46 | files_need_boilerplate=() 47 | while IFS=$'\n' read -r line; do 48 | files_need_boilerplate+=( "$line" ) 49 | done < <("${boiler}" "${files[@]}") 50 | 51 | # Run boilerplate check 52 | if [[ ${#files_need_boilerplate[@]} -gt 0 ]]; then 53 | for file in "${files_need_boilerplate[@]}"; do 54 | echo "Boilerplate header is wrong for: ${file}" >&2 55 | done 56 | exit 1 57 | fi 58 | -------------------------------------------------------------------------------- /pkg/utils/graph.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "github.com/pingcap/log" 18 | "go.uber.org/zap" 19 | ) 20 | 21 | // Edge represents an edge in graph 22 | type Edge struct { 23 | Source uint32 24 | Target uint32 25 | Next *Edge 26 | } 27 | 28 | // Graph represents a graph with link list 29 | type Graph struct { 30 | head map[uint32]*Edge 31 | } 32 | 33 | // NewGraph creates a Graph 34 | func NewGraph() *Graph { 35 | return &Graph{ 36 | head: make(map[uint32]*Edge), 37 | } 38 | } 39 | 40 | // Insert inserts an Edge into a graph from source to target 41 | func (g *Graph) Insert(source uint32, target uint32) { 42 | newEdge := Edge{ 43 | Source: source, 44 | Target: target, 45 | Next: g.head[source], 46 | } 47 | g.head[source] = &newEdge 48 | } 49 | 50 | // IterFrom starts iterating from source node 51 | func (g *Graph) IterFrom(source uint32) *Edge { 52 | return g.head[source] 53 | } 54 | 55 | // Flatten flattens the subtree from source (without checking whether it's a tree) 56 | func (g *Graph) Flatten(source uint32) []uint32 { 57 | current := g.head[source] 58 | 59 | var flatTree []uint32 60 | for { 61 | if current == nil { 62 | break 63 | } 64 | 65 | children := g.Flatten(current.Target) 66 | flatTree = append(flatTree, current.Target) 67 | flatTree = append(flatTree, children...) 68 | 69 | current = current.Next 70 | } 71 | 72 | log.Debug("get flatTree", zap.Uint32("source", source), zap.Uint32s("flatTree", flatTree)) 73 | return flatTree 74 | } 75 | -------------------------------------------------------------------------------- /pkg/utils/cidr_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "testing" 18 | 19 | . "github.com/onsi/gomega" 20 | ) 21 | 22 | // TODO: support more cases such as IPv6 contained IPv4 23 | func TestIPToCidr(t *testing.T) { 24 | g := NewGomegaWithT(t) 25 | type TestCase struct { 26 | name string 27 | ip string 28 | expectedValue string 29 | } 30 | tcs := []TestCase{ 31 | { 32 | name: "valid ipv4", 33 | ip: "172.8.4.2", 34 | expectedValue: "172.8.4.2/32", 35 | }, 36 | { 37 | name: "valid ipv6", 38 | ip: "2001:da8:215:4020:226:b9ff:fe2c:54f", 39 | expectedValue: "2001:da8:215:4020:226:b9ff:fe2c:54f/128", 40 | }, 41 | } 42 | for _, tc := range tcs { 43 | g.Expect(IPToCidr(tc.ip)).To(Equal(tc.expectedValue)) 44 | } 45 | } 46 | 47 | func TestResolveCidrs(t *testing.T) { 48 | type TestCase struct { 49 | name string 50 | names []string 51 | expectedValue []string 52 | } 53 | g := NewGomegaWithT(t) 54 | tcs := []TestCase{ 55 | { 56 | // TODO: the last one need further discussion. 57 | name: "valid names", 58 | names: []string{"192.0.2.1/24", "2001:db8:a0b:12f0::1/32", "::1", "2001:da8:215:4020:226:b9ff:fe2c:54f"}, 59 | expectedValue: []string{"192.0.2.0/24", "2001:db8::/32", "::1/128", "2001:da8:215:4020:226:b9ff:fe2c:54f/128"}, 60 | }, 61 | } 62 | 63 | for _, tc := range tcs { 64 | g.Expect(ResolveCidrs(tc.names)).To(Equal(tc.expectedValue)) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /pkg/server/chaosd/user_defined.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "os/exec" 18 | 19 | "github.com/pingcap/log" 20 | "github.com/pkg/errors" 21 | "go.uber.org/zap" 22 | 23 | "github.com/chaos-mesh/chaosd/pkg/core" 24 | ) 25 | 26 | type userDefinedAttack struct{} 27 | 28 | var UserDefinedAttack AttackType = userDefinedAttack{} 29 | 30 | func (userDefinedAttack) Attack(options core.AttackConfig, _ Environment) error { 31 | option := options.(*core.UserDefinedOption) 32 | log.Info("attack command", zap.String("command", option.AttackCmd)) 33 | 34 | cmd := exec.Command("bash", "-c", option.AttackCmd) 35 | output, err := cmd.CombinedOutput() 36 | if err != nil { 37 | return errors.Wrap(err, string(output)) 38 | } 39 | if len(output) > 0 { 40 | log.Info("attack command", zap.String("output", string(output))) 41 | } 42 | 43 | return nil 44 | } 45 | 46 | func (userDefinedAttack) Recover(exp core.Experiment, _ Environment) error { 47 | config, err := exp.GetRequestCommand() 48 | if err != nil { 49 | return err 50 | } 51 | option := config.(*core.UserDefinedOption) 52 | log.Info("recover command", zap.String("command", option.RecoverCmd)) 53 | 54 | cmd := exec.Command("bash", "-c", option.RecoverCmd) 55 | output, err := cmd.CombinedOutput() 56 | if err != nil { 57 | return errors.Wrap(err, string(output)) 58 | } 59 | if len(output) > 0 { 60 | log.Info("recover command", zap.String("command", option.RecoverCmd), zap.String("output", string(output))) 61 | } 62 | 63 | return nil 64 | } 65 | -------------------------------------------------------------------------------- /pkg/core/experiment_run.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "context" 18 | "time" 19 | 20 | "github.com/google/uuid" 21 | ) 22 | 23 | const ( 24 | RunStarted = "started" 25 | RunFailed = "failed" 26 | RunSuccess = "success" 27 | RunRecovered = "recovered" 28 | ) 29 | 30 | // ExperimentRunStore defines operations for working with experiment runs 31 | type ExperimentRunStore interface { 32 | ListByExperimentID(ctx context.Context, id uint) ([]*ExperimentRun, error) 33 | ListByExperimentUID(ctx context.Context, uid string) ([]*ExperimentRun, error) 34 | LatestRun(ctx context.Context, id uint) (*ExperimentRun, error) 35 | 36 | NewRun(ctx context.Context, expRun *ExperimentRun) error 37 | Update(ctx context.Context, runUid string, status string, message string) error 38 | } 39 | 40 | // ExperimentRun represents a run of an experiment 41 | type ExperimentRun struct { 42 | ID uint `gorm:"primary_key" json:"id"` 43 | UID string `gorm:"index:uid" json:"uid"` 44 | StartAt time.Time `gorm:"autoCreateTime" json:"start_at"` 45 | FinishedAt time.Time `json:"finished_at"` 46 | Status string `json:"status"` 47 | Message string `json:"error"` 48 | ExperimentID uint 49 | Experiment Experiment `gorm:"foreignKey:ExperimentID" json:"experiment"` 50 | } 51 | 52 | func (exp Experiment) NewRun() *ExperimentRun { 53 | return &ExperimentRun{ 54 | ExperimentID: exp.ID, 55 | // TODO: maybe need to use specified uid 56 | UID: uuid.New().String(), 57 | Status: RunStarted, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tools/file/replace.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "fmt" 18 | "os/exec" 19 | 20 | "github.com/pingcap/errors" 21 | "github.com/pingcap/log" 22 | "github.com/spf13/cobra" 23 | "go.uber.org/zap" 24 | ) 25 | 26 | func NewFileReplaceCommand() *cobra.Command { 27 | var file, originStr, destStr string 28 | var line int 29 | 30 | cmd := &cobra.Command{ 31 | Use: "replace", 32 | Short: "replace data in file", 33 | 34 | Run: func(*cobra.Command, []string) { 35 | exit(replaceFile(file, originStr, destStr, line)) 36 | }, 37 | } 38 | 39 | cmd.Flags().StringVarP(&file, "file-name", "f", "", "replace data in the file") 40 | cmd.Flags().StringVarP(&originStr, "origin-string", "o", "", "the origin string to be replaced") 41 | cmd.Flags().StringVarP(&destStr, "dest-string", "d", "", "the destination string to replace the origin string") 42 | cmd.Flags().IntVarP(&line, "line", "l", 0, "the line number to replace, default is 0, means replace all lines") 43 | 44 | return cmd 45 | } 46 | 47 | func replaceFile(file, originStr, destStr string, line int) error { 48 | var cmdStr string 49 | if line == 0 { 50 | cmdStr = fmt.Sprintf("sed -i 's/%s/%s/g' %s", originStr, destStr, file) 51 | } else { 52 | cmdStr = fmt.Sprintf("sed -i '%d s/%s/%s/g' %s", line, originStr, destStr, file) 53 | } 54 | 55 | cmd := exec.Command("bash", "-c", cmdStr) 56 | output, err := cmd.CombinedOutput() 57 | if err != nil { 58 | log.Error(string(output), zap.Error(err)) 59 | return errors.WithStack(err) 60 | } 61 | if len(output) > 0 { 62 | log.Info(string(output)) 63 | } 64 | 65 | return nil 66 | } 67 | -------------------------------------------------------------------------------- /pkg/utils/cidr.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "net" 18 | "strings" 19 | ) 20 | 21 | // IPToCidr converts from an ip to a full mask cidr 22 | func IPToCidr(ip string) string { 23 | // TODO: support IPv6 correctly 24 | 25 | // distinguish is IPv4 or IPv6 address 26 | // no error checking here! 27 | if net.ParseIP(ip).To4() != nil { 28 | return ip + "/32" 29 | } 30 | return ip + "/128" 31 | } 32 | 33 | // ResolveCidrs converts multiple cidrs/ips/domains into cidr 34 | func ResolveCidrs(names []string) ([]string, error) { 35 | cidrs := []string{} 36 | for _, target := range names { 37 | // TODO: resolve ip on every pods but not in controller, in case the dns server of these pods differ 38 | cidr, err := ResolveCidr(target) 39 | if err != nil { 40 | return nil, err 41 | } 42 | 43 | cidrs = append(cidrs, cidr...) 44 | } 45 | 46 | return cidrs, nil 47 | } 48 | 49 | // ResolveCidr converts cidr/ip/domain into cidr 50 | func ResolveCidr(name string) ([]string, error) { 51 | _, ipnet, err := net.ParseCIDR(name) 52 | if err == nil { 53 | return []string{ipnet.String()}, nil 54 | } 55 | 56 | // name is not CIDR, check if it is invalid IP address 57 | if net.ParseIP(name) != nil { 58 | return []string{IPToCidr(name)}, nil 59 | } 60 | 61 | addrs, err := net.LookupIP(name) 62 | if err != nil { 63 | return nil, err 64 | } 65 | 66 | cidrs := []string{} 67 | for _, addr := range addrs { 68 | addr := addr.String() 69 | 70 | // TODO: support IPv6 71 | if strings.Contains(addr, ".") { 72 | cidrs = append(cidrs, IPToCidr(addr)) 73 | } 74 | } 75 | return cidrs, nil 76 | } 77 | -------------------------------------------------------------------------------- /pkg/server/chaosd/disk_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package chaosd 15 | 16 | import ( 17 | "os" 18 | "testing" 19 | 20 | "github.com/stretchr/testify/assert" 21 | 22 | "github.com/chaos-mesh/chaosd/pkg/core" 23 | "github.com/chaos-mesh/chaosd/pkg/utils" 24 | ) 25 | 26 | func Test_diskAttack_Attack(t *testing.T) { 27 | opt := core.DiskOption{ 28 | CommonAttackConfig: core.CommonAttackConfig{ 29 | Action: core.DiskFillAction, 30 | }, 31 | Size: "10M", 32 | Path: "./a", 33 | PayloadProcessNum: 1, 34 | } 35 | env := Environment{ 36 | AttackUid: "a", 37 | Chaos: &Server{ 38 | CmdPools: make(map[string]*utils.CommandPools), 39 | }, 40 | } 41 | conf, err := opt.PreProcess() 42 | assert.NoError(t, err) 43 | err = DiskAttack.Attack(conf, env) 44 | assert.NoError(t, err) 45 | 46 | f, err := os.Open("./a") 47 | assert.NoError(t, err) 48 | fi, err := f.Stat() 49 | assert.NoError(t, err) 50 | assert.Equal(t, int64(10), fi.Size()>>20) 51 | err = os.Remove("./a") 52 | assert.NoError(t, err) 53 | 54 | opt.Action = core.DiskWritePayloadAction 55 | opt.PayloadProcessNum = 4 56 | wConf, err := opt.PreProcess() 57 | assert.NoError(t, err) 58 | err = DiskAttack.Attack(wConf, env) 59 | assert.NoError(t, err) 60 | 61 | f, err = os.Open("./a") 62 | assert.NoError(t, err) 63 | fi, err = f.Stat() 64 | assert.NoError(t, err) 65 | assert.Equal(t, fi.Size()>>20, int64(2)) 66 | err = os.Remove("./a") 67 | assert.NoError(t, err) 68 | 69 | opt.Action = core.DiskReadPayloadAction 70 | opt.PayloadProcessNum = 4 71 | opt.Path = "./" 72 | _, err = opt.PreProcess() 73 | assert.Error(t, err) 74 | } 75 | -------------------------------------------------------------------------------- /cmd/attack/user_defined.go: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package attack 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/spf13/cobra" 20 | "go.uber.org/fx" 21 | 22 | "github.com/chaos-mesh/chaosd/cmd/server" 23 | "github.com/chaos-mesh/chaosd/pkg/core" 24 | "github.com/chaos-mesh/chaosd/pkg/server/chaosd" 25 | "github.com/chaos-mesh/chaosd/pkg/utils" 26 | ) 27 | 28 | func NewUserDefinedCommand(uid *string) *cobra.Command { 29 | options := core.NewUserDefinedOption() 30 | dep := fx.Options( 31 | server.Module, 32 | fx.Provide(func() *core.UserDefinedOption { 33 | options.UID = *uid 34 | return options 35 | }), 36 | ) 37 | 38 | cmd := &cobra.Command{ 39 | Use: "user-defined ", 40 | Short: "user defined attack related commands", 41 | Run: func(*cobra.Command, []string) { 42 | options.CompleteDefaults() 43 | utils.FxNewAppWithoutLog(dep, fx.Invoke(userDefinedAttackFunc)).Run() 44 | }, 45 | } 46 | 47 | cmd.Flags().StringVarP(&options.AttackCmd, "attack-cmd", "a", "", "the command to be executed when attack") 48 | cmd.Flags().StringVarP(&options.RecoverCmd, "recover-cmd", "r", "", "the command to be executed when recover") 49 | 50 | return cmd 51 | } 52 | 53 | func userDefinedAttackFunc(options *core.UserDefinedOption, chaos *chaosd.Server) { 54 | if err := options.Validate(); err != nil { 55 | utils.ExitWithError(utils.ExitBadArgs, err) 56 | } 57 | 58 | uid, err := chaos.ExecuteAttack(chaosd.UserDefinedAttack, options, core.CommandMode) 59 | if err != nil { 60 | utils.ExitWithError(utils.ExitError, err) 61 | } 62 | 63 | utils.NormalExit(fmt.Sprintf("Attack user defined comamnd successfully, uid: %s", uid)) 64 | } 65 | -------------------------------------------------------------------------------- /pkg/client/request.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package client 15 | 16 | import ( 17 | "bytes" 18 | "io" 19 | "io/ioutil" 20 | "net/http" 21 | 22 | "github.com/pingcap/errors" 23 | ) 24 | 25 | // BodyOption sets the type and content of the body 26 | type BodyOption func(*bodyOption) 27 | 28 | type bodyOption struct { 29 | contentType string 30 | body io.Reader 31 | } 32 | 33 | func withJsonBody(body []byte) BodyOption { 34 | return func(bo *bodyOption) { 35 | bo.contentType = "application/json" 36 | bo.body = bytes.NewBuffer(body) 37 | } 38 | } 39 | 40 | func doRequest( 41 | cli *http.Client, 42 | url, method string, 43 | opts ...BodyOption, 44 | ) ([]byte, []byte, error) { 45 | b := &bodyOption{} 46 | for _, o := range opts { 47 | o(b) 48 | } 49 | req, err := http.NewRequest(method, url, b.body) 50 | if err != nil { 51 | return nil, nil, errors.WithStack(err) 52 | } 53 | 54 | if b.contentType != "" { 55 | req.Header.Set("Content-Type", b.contentType) 56 | } 57 | 58 | resp, apiErr, err := dial(cli, req) 59 | if err != nil { 60 | return nil, nil, errors.WithStack(err) 61 | } 62 | 63 | return resp, apiErr, nil 64 | } 65 | 66 | func dial(cli *http.Client, req *http.Request) ([]byte, []byte, error) { 67 | resp, err := cli.Do(req) 68 | if err != nil { 69 | return nil, nil, err 70 | } 71 | defer resp.Body.Close() 72 | if resp.StatusCode != http.StatusOK { 73 | var apiErr []byte 74 | apiErr, err = ioutil.ReadAll(resp.Body) 75 | if err != nil { 76 | return nil, nil, err 77 | } 78 | return nil, apiErr, nil 79 | } 80 | 81 | content, err := ioutil.ReadAll(resp.Body) 82 | if err != nil { 83 | return nil, nil, err 84 | } 85 | return content, nil, nil 86 | } 87 | -------------------------------------------------------------------------------- /pkg/store/dbstore/store.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package dbstore 15 | 16 | import ( 17 | "path" 18 | 19 | "go.uber.org/zap" 20 | 21 | "gorm.io/driver/sqlite" 22 | "gorm.io/gorm" 23 | "gorm.io/gorm/logger" 24 | 25 | "github.com/pingcap/log" 26 | 27 | "github.com/chaos-mesh/chaosd/pkg/utils" 28 | ) 29 | 30 | const dataFile = "chaosd.dat" 31 | 32 | // DB defines a db storage. 33 | type DB struct { 34 | *gorm.DB 35 | } 36 | 37 | // NewDBStore returns a new DB 38 | func NewDBStore() (*DB, error) { 39 | dsn := path.Join(utils.GetProgramPath(), dataFile) 40 | 41 | // fix error `database is locked`, refer to https://github.com/mattn/go-sqlite3/blob/master/README.md#faq 42 | dsn += "?cache=shared" 43 | 44 | gormDB, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{ 45 | Logger: logger.Default.LogMode(logger.Silent), 46 | }) 47 | if err != nil { 48 | log.Error("failed to open DB", zap.Error(err)) 49 | return nil, err 50 | } 51 | 52 | tempDB, err := gormDB.DB() 53 | if err != nil { 54 | log.Error("failed to get DB", zap.Error(err)) 55 | return nil, err 56 | } 57 | // fix error `database is locked`, refer to https://github.com/mattn/go-sqlite3/blob/master/README.md#faq 58 | tempDB.SetMaxOpenConns(1) 59 | 60 | db := &DB{ 61 | gormDB, 62 | } 63 | 64 | return db, nil 65 | } 66 | 67 | //func DryDBStore() (*DB, error) { 68 | // gormDB, err := gorm.Open(sqlite.Open(path.Join(utils.GetProgramPath(), dataFile)), &gorm.Config{ 69 | // Logger: logger.Default.LogMode(logger.Silent), 70 | // }) 71 | // if err != nil { 72 | // log.Error("failed to open DB", zap.Error(err)) 73 | // return nil, err 74 | // } 75 | // 76 | // db := &DB{ 77 | // gormDB, 78 | // } 79 | // 80 | // return db, nil 81 | //} 82 | -------------------------------------------------------------------------------- /pkg/mock/mock.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package mock 15 | 16 | import ( 17 | "path" 18 | "reflect" 19 | "sync" 20 | 21 | "github.com/pingcap/failpoint" 22 | ) 23 | 24 | // Finalizer represent the function that clean a mock point 25 | type Finalizer func() error 26 | 27 | type mockPoints struct { 28 | m map[string]interface{} 29 | l sync.Mutex 30 | } 31 | 32 | func (p *mockPoints) set(fpname string, value interface{}) { 33 | p.l.Lock() 34 | defer p.l.Unlock() 35 | 36 | p.m[fpname] = value 37 | } 38 | 39 | func (p *mockPoints) get(fpname string) interface{} { 40 | p.l.Lock() 41 | defer p.l.Unlock() 42 | 43 | return p.m[fpname] 44 | } 45 | 46 | func (p *mockPoints) clr(fpname string) { 47 | p.l.Lock() 48 | defer p.l.Unlock() 49 | 50 | delete(p.m, fpname) 51 | } 52 | 53 | var points = mockPoints{m: make(map[string]interface{})} 54 | 55 | // On inject a failpoint 56 | func On(fpname string) interface{} { 57 | var ret interface{} 58 | failpoint.Inject(fpname, func() { 59 | ret = points.get(fpname) 60 | }) 61 | return ret 62 | } 63 | 64 | // With enable failpoint and provide a value 65 | func With(fpname string, value interface{}) Finalizer { 66 | if err := failpoint.Enable(failpath(fpname), "return(true)"); err != nil { 67 | panic(err) 68 | } 69 | points.set(fpname, value) 70 | return func() error { return Reset(fpname) } 71 | } 72 | 73 | // Reset disable failpoint and remove mock value 74 | func Reset(fpname string) error { 75 | if err := failpoint.Disable(failpath(fpname)); err != nil { 76 | return err 77 | } 78 | points.clr(fpname) 79 | return nil 80 | } 81 | 82 | func failpath(fpname string) string { 83 | type em struct{} 84 | return path.Join(reflect.TypeOf(em{}).PkgPath(), fpname) 85 | } 86 | -------------------------------------------------------------------------------- /pkg/utils/check.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "net" 18 | "strconv" 19 | "strings" 20 | ) 21 | 22 | func CheckPorts(p string) bool { 23 | if len(p) == 0 { 24 | return true 25 | } 26 | 27 | ports := strings.Split(p, ",") 28 | for _, p := range ports { 29 | if len(p) == 0 { 30 | return false 31 | } 32 | 33 | ps := strings.Split(p, ":") 34 | if len(ps) == 0 { 35 | if _, err := strconv.Atoi(p); err != nil { 36 | return false 37 | } 38 | continue 39 | } 40 | 41 | if len(ps) > 2 { 42 | return false 43 | } 44 | 45 | for _, pp := range ps { 46 | if _, err := strconv.Atoi(pp); err != nil { 47 | return false 48 | } 49 | } 50 | } 51 | 52 | return true 53 | } 54 | 55 | func CheckIPs(i string) bool { 56 | if len(i) == 0 { 57 | return true 58 | } 59 | 60 | ips := strings.Split(i, ",") 61 | for _, ip := range ips { 62 | if !strings.Contains(ip, "/") { 63 | if net.ParseIP(ip) == nil { 64 | return false 65 | } 66 | continue 67 | } 68 | 69 | if _, _, err := net.ParseCIDR(ip); err != nil { 70 | return false 71 | } 72 | } 73 | 74 | return true 75 | } 76 | 77 | func CheckIPProtocols(p string) bool { 78 | if len(p) == 0 { 79 | return true 80 | } 81 | 82 | if p == "tcp" || p == "udp" || p == "icmp" || p == "all" { 83 | return true 84 | } 85 | 86 | return false 87 | } 88 | 89 | func CheckPercent(p string) bool { 90 | if len(p) == 0 { 91 | return true 92 | } 93 | 94 | v, err := strconv.ParseFloat(p, 32) 95 | if err != nil { 96 | return false 97 | } 98 | 99 | if v < 0 || v > 100 { 100 | return false 101 | } 102 | 103 | return true 104 | } 105 | -------------------------------------------------------------------------------- /pkg/server/utils/error.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "fmt" 18 | "net/http" 19 | 20 | "github.com/gin-gonic/gin" 21 | "github.com/joomcode/errorx" 22 | ) 23 | 24 | var ( 25 | ErrNS = errorx.NewNamespace("error.api") 26 | ErrAuth = ErrNS.NewType("auth") 27 | ErrOther = ErrNS.NewType("other") 28 | ErrInvalidRequest = ErrNS.NewType("invalid_request") 29 | ErrInternalServer = ErrNS.NewType("internal_server_error") 30 | ErrNotFound = ErrNS.NewType("resource_not_found") 31 | ) 32 | 33 | type APIError struct { 34 | Error bool `json:"error"` 35 | Message string `json:"message"` 36 | Code string `json:"code"` 37 | FullText string `json:"full_text"` 38 | } 39 | 40 | // MWHandleErrors creates a middleware that turns (last) error in the context into an APIError json response. 41 | // In handlers, `c.Error(err)` can be used to attach the error to the context. 42 | // When error is attached in the context: 43 | // - The handler can optionally assign the HTTP status code. 44 | // - The handler must not self-generate a response body. 45 | func MWHandleErrors() gin.HandlerFunc { 46 | return func(c *gin.Context) { 47 | c.Next() 48 | 49 | err := c.Errors.Last() 50 | if err == nil { 51 | return 52 | } 53 | 54 | statusCode := c.Writer.Status() 55 | if statusCode == http.StatusOK { 56 | statusCode = http.StatusInternalServerError 57 | } 58 | 59 | innerErr := errorx.Cast(err.Err) 60 | if innerErr == nil { 61 | innerErr = ErrOther.WrapWithNoMessage(err.Err) 62 | } 63 | 64 | c.AbortWithStatusJSON(statusCode, APIError{ 65 | Error: true, 66 | Message: innerErr.Error(), 67 | Code: errorx.GetTypeName(innerErr), 68 | FullText: fmt.Sprintf("%+v", innerErr), 69 | }) 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /hack/version.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -euo pipefail 17 | 18 | function chaosd::version::get_version_vars() { 19 | if [[ -n ${GIT_COMMIT-} ]] || GIT_COMMIT=$(git rev-parse "HEAD^{commit}" 2>/dev/null); then 20 | # Use git describe to find the version based on tags. 21 | # --always would show the unique abbr commit as fallback. 22 | if [[ -n ${GIT_VERSION-} ]] || GIT_VERSION=$(git describe --always --tags --abbrev=14 "${GIT_COMMIT}^{commit}" 2>/dev/null); then 23 | # if current commit is not on a certain tag 24 | if ! git describe --tags --exact-match >/dev/null 2>&1 ; then 25 | # GIT_VERSION=gitBranch-gitCommitHash 26 | IFS='-' read -ra GIT_ARRAY <<< "$GIT_VERSION" 27 | GIT_VERSION=$(git rev-parse --abbrev-ref HEAD)-${GIT_ARRAY[${#GIT_ARRAY[@]}-1]} 28 | fi 29 | fi 30 | fi 31 | } 32 | 33 | function chaosd::version::ldflag() { 34 | local key=${1} 35 | local val=${2} 36 | 37 | echo "-X 'github.com/chaos-mesh/chaosd/pkg/version.${key}=${val}'" 38 | } 39 | 40 | # Prints the value that needs to be passed to the -ldflags parameter of go build 41 | function chaosd::version::ldflags() { 42 | chaosd::version::get_version_vars 43 | 44 | local buildDate= 45 | [[ -z ${SOURCE_DATE_EPOCH-} ]] || buildDate="--date=@${SOURCE_DATE_EPOCH}" 46 | local -a ldflags=($(chaosd::version::ldflag "buildDate" "$(date ${buildDate} -u +'%Y-%m-%dT%H:%M:%SZ')")) 47 | if [[ -n ${GIT_COMMIT-} ]]; then 48 | ldflags+=($(chaosd::version::ldflag "gitCommit" "${GIT_COMMIT}")) 49 | fi 50 | 51 | if [[ -n ${GIT_VERSION-} ]]; then 52 | ldflags+=($(chaosd::version::ldflag "gitVersion" "${GIT_VERSION}")) 53 | fi 54 | 55 | # The -ldflags parameter takes a single string, so join the output. 56 | echo "${ldflags[*]-}" 57 | } 58 | 59 | # output -ldflags parameters 60 | chaosd::version::ldflags 61 | -------------------------------------------------------------------------------- /test/integration_test/mtls_server/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2021 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -u 17 | 18 | cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 19 | cd $cur 20 | 21 | bin_path=../../../bin 22 | 23 | RED='\033[0;31m' 24 | NC='\033[0m' # No Color 25 | HTTPS_PORT=31768 26 | ENDPOINT="https://localhost:$HTTPS_PORT/api/experiments" 27 | 28 | function failtest() { 29 | msg="$1" 30 | kill $server_pid 31 | echo -e "${RED}FAIL: $msg$NC" 32 | exit 1 33 | } 34 | 35 | function request() { 36 | cert_prefix=$1 37 | result_status_code=$2 38 | cmd="curl -Lskw \n%{http_code} $ENDPOINT" 39 | if [[ -n "$cert_prefix" ]]; then 40 | cmd="$cmd --cert client/${cert_prefix}_cert.pem --key client/${cert_prefix}_key.pem" 41 | fi 42 | response=$($cmd) 43 | body=$(echo "$response" | head -n1) 44 | status=$(echo "$response" | tail -n1) 45 | if [[ "$status" != "$result_status_code" ]]; then 46 | failtest "expected $result_status_code, got $status" 47 | fi 48 | } 49 | 50 | echo "Generating certificates" 51 | bash +ex ./gen_certs.sh 52 | 53 | echo "Starting Server in mTLS mode" 54 | ${bin_path}/chaosd server \ 55 | --https-port $HTTPS_PORT \ 56 | --cert ./server/server_cert.pem \ 57 | --key ./server/server_key.pem \ 58 | --CA ./server/server_cert.pem \ 59 | > server.out & 60 | 61 | server_pid=$! 62 | 63 | sleep 2 64 | 65 | if ! kill -0 $server_pid > /dev/null 2>&1; then 66 | echo -e "${RED}ERROR: Couldn't start server$NC" 67 | cat server.out 68 | exit 1 69 | fi 70 | 71 | echo -n "Test with valid certificate... " 72 | request 'valid' 200 73 | echo "Passed" 74 | 75 | echo -n "Test with no certificate... " 76 | request '' 401 77 | echo "Passed" 78 | 79 | echo -n "Test with invalid certificate... " 80 | request 'invalid' 403 81 | echo "Passed" 82 | 83 | kill $server_pid 84 | rm -f server.out 85 | rm -rf client server -------------------------------------------------------------------------------- /cmd/attack/clock.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package attack 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/spf13/cobra" 20 | "go.uber.org/fx" 21 | 22 | "github.com/chaos-mesh/chaosd/cmd/server" 23 | "github.com/chaos-mesh/chaosd/pkg/core" 24 | "github.com/chaos-mesh/chaosd/pkg/server/chaosd" 25 | "github.com/chaos-mesh/chaosd/pkg/utils" 26 | ) 27 | 28 | func NewClockAttackCommand(uid *string) *cobra.Command { 29 | options := core.NewClockOption() 30 | dep := fx.Options( 31 | server.Module, 32 | fx.Provide(func() *core.ClockOption { 33 | options.UID = *uid 34 | return options 35 | }), 36 | ) 37 | 38 | cmd := &cobra.Command{ 39 | Use: "clock attack", 40 | Short: "clock skew", 41 | Run: func(*cobra.Command, []string) { 42 | options.Action = core.ClockAction 43 | utils.FxNewAppWithoutLog(dep, fx.Invoke(processClockAttack)).Run() 44 | }, 45 | } 46 | 47 | cmd.Flags().IntVarP(&options.Pid, "pid", "p", 0, "Pid of target program.") 48 | cmd.Flags().StringVarP(&options.TimeOffset, "time-offset", "t", "", "Specifies the length of time offset.") 49 | cmd.Flags().StringVarP(&options.ClockIdsSlice, "clock-ids-slice", "c", "CLOCK_REALTIME", 50 | "The identifier of the particular clock on which to act."+ 51 | "More clock description in linux kernel can be found in man page of clock_getres, clock_gettime, clock_settime."+ 52 | "Muti clock ids should be split with \",\"") 53 | return cmd 54 | } 55 | 56 | func processClockAttack(options *core.ClockOption, chaos *chaosd.Server) { 57 | err := options.PreProcess() 58 | if err != nil { 59 | utils.ExitWithError(utils.ExitBadArgs, err) 60 | } 61 | 62 | uid, err := chaos.ExecuteAttack(chaosd.ClockAttack, options, core.CommandMode) 63 | if err != nil { 64 | utils.ExitWithError(utils.ExitError, err) 65 | } 66 | 67 | utils.NormalExit(fmt.Sprintf("Clock attack %v successfully, uid: %s", options, uid)) 68 | } 69 | -------------------------------------------------------------------------------- /test/integration_test/stress/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -eu 17 | 18 | cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 19 | cd $cur 20 | 21 | bin_path=../../../bin 22 | 23 | echo "download memStress && set environment variable" 24 | if [[ ! (-e memStress_v0.3-x86_64-linux-gnu.tar.gz) ]]; then 25 | curl -fsSL -o memStress_v0.3-x86_64-linux-gnu.tar.gz https://github.com/chaos-mesh/memStress/releases/download/v0.3/memStress_v0.3-x86_64-linux-gnu.tar.gz 26 | tar zxvf memStress_v0.3-x86_64-linux-gnu.tar.gz 27 | fi 28 | 29 | # test cpu stress 30 | ${bin_path}/chaosd attack stress cpu -l 10 -w 1 > cpu.out 31 | 32 | PID=`cat cpu.out | grep "stress-ng" | sed 's/.*Pid=\([0-9]*\).*/\1/g'` 33 | 34 | stress_ng_num=`ps aux > test.temp && grep "stress-ng" test.temp | wc -l && rm test.temp` 35 | if [ ${stress_ng_num} -lt 1 ]; then 36 | echo "stress-ng is not run when executing stress cpu attack" 37 | exit 1 38 | fi 39 | 40 | uid=`cat cpu.out | grep "Attack stress cpu successfully" | awk -F: '{print $2}'` 41 | ${bin_path}/chaosd recover ${uid} 42 | 43 | echo "wait stress-ng $PID exit after recovering stress cpu attack" 44 | timeout 5s tail --pid=$PID -f /dev/null 45 | 46 | ps aux | grep stress-ng 47 | 48 | # test mem stress 49 | ${bin_path}/chaosd attack stress mem --size 10M > mem.out 50 | 51 | PID=`cat mem.out | grep "memStress" | sed 's/.*Pid=\([0-9]*\).*/\1/g'` 52 | 53 | memStress_num=`ps aux > test.temp && grep "memStress" test.temp | wc -l && rm test.temp` 54 | if [ ${memStress_num} -lt 1 ]; then 55 | echo "memStress is not run when executing stress mem attack" 56 | exit 1 57 | fi 58 | 59 | uid=`cat mem.out | grep "Attack stress mem successfully" | awk -F: '{print $2}'` 60 | ${bin_path}/chaosd recover ${uid} 61 | 62 | echo "wait memStress $PID exit after recovering stress mem attack" 63 | timeout 5s tail --pid=$PID -f /dev/null 64 | 65 | ps aux | grep memStress 66 | 67 | rm cpu.out 68 | rm mem.out -------------------------------------------------------------------------------- /test/integration_test/process/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright 2020 Chaos Mesh Authors. 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | 16 | set -u 17 | 18 | cur=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) 19 | cd $cur 20 | 21 | bin_path=../../../bin 22 | 23 | ${bin_path}/dummy > dummy.out & 24 | 25 | sleep 1 26 | 27 | pid=$(cat dummy.out) 28 | 29 | # test stop attack 30 | ${bin_path}/chaosd attack process stop -p ${pid} > proc.out 31 | 32 | sleep 1 33 | 34 | uid=$(cat proc.out | grep "Attack process ${pid} successfully" | awk -F: '{print $2}') 35 | 36 | stat=$(ps axo pid,s | grep ${pid} | awk '{print $2}') 37 | 38 | # T for stopped 39 | if [[ ${stat} != "T" ]]; then 40 | echo "target process is not stopped by processed stop attack" 41 | rm dummy.out 42 | rm proc.out 43 | exit 1 44 | fi 45 | 46 | # test recover from stop attack 47 | ${bin_path}/chaosd recover ${uid} 48 | 49 | sleep 1 50 | 51 | stat=$(ps axo pid,s | grep ${pid} | awk '{print $2}') 52 | 53 | # S for sleeping 54 | if [[ ${stat} != "S" ]]; then 55 | echo "target process is not resumed by recovering from process stop attack" 56 | rm dummy.out 57 | rm proc.out 58 | exit 1 59 | fi 60 | 61 | # test kill attack and recover-cmd 62 | ${bin_path}/chaosd attack process kill -p ${pid} -r "echo \"recover process\" >> proc.out" > proc.out 63 | 64 | sleep 1 65 | 66 | uid=$(cat proc.out | grep "Attack process ${pid} successfully" | awk -F: '{print $2}') 67 | stat=$(ps axo pid | grep ${pid}) 68 | 69 | # test kill attack 70 | if [[ -n ${stat} ]]; then 71 | echo "target process is not killed by processed kill attack" 72 | rm dummy.out 73 | rm proc.out 74 | kill ${pid} 75 | exit 1 76 | fi 77 | 78 | # test recover-cmd 79 | ${bin_path}/chaosd recover ${uid} 80 | recover_result=$(cat proc.out | awk 'END {print}') 81 | 82 | if [[ ${recover_result} != "recover process" ]]; then 83 | echo "target recover process is not executed" 84 | rm dummy.out 85 | rm proc.out 86 | exit 1 87 | fi 88 | 89 | 90 | rm dummy.out 91 | rm proc.out 92 | 93 | exit 0 94 | -------------------------------------------------------------------------------- /pkg/core/common.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package core 15 | 16 | import ( 17 | "time" 18 | 19 | "github.com/pingcap/errors" 20 | ) 21 | 22 | type AttackConfig interface { 23 | Validate() error 24 | Cron() string 25 | ScheduleDuration() (*time.Duration, error) 26 | // String is replacement of .Action 27 | String() string 28 | // RecoverData is replacement of earlier .String() 29 | RecoverData() string 30 | 31 | // AttackKind returns the kind of attack 32 | AttackKind() string 33 | 34 | // CompleteDefaults is used to fill flags with default values 35 | CompleteDefaults() 36 | 37 | // GetUID returns the experiment's ID 38 | GetUID() string 39 | } 40 | 41 | type SchedulerConfig struct { 42 | Schedule string `json:"schedule"` 43 | Duration string `json:"duration"` 44 | } 45 | 46 | func (config SchedulerConfig) Cron() string { 47 | return config.Schedule 48 | } 49 | 50 | func (config SchedulerConfig) ScheduleDuration() (*time.Duration, error) { 51 | if len(config.Duration) == 0 { 52 | return nil, nil 53 | } 54 | duration, err := time.ParseDuration(config.Duration) 55 | return &duration, err 56 | } 57 | 58 | type CommonAttackConfig struct { 59 | SchedulerConfig 60 | 61 | Action string `json:"action"` 62 | Kind string `json:"kind"` 63 | UID string `json:"uid"` 64 | } 65 | 66 | func (config CommonAttackConfig) String() string { 67 | return config.Action 68 | } 69 | 70 | func (config CommonAttackConfig) AttackKind() string { 71 | return config.Kind 72 | } 73 | 74 | // CompleteDefaults no-op implementation 75 | func (config *CommonAttackConfig) CompleteDefaults() {} 76 | 77 | // Validate does a basic validation of common parameters 78 | func (config *CommonAttackConfig) Validate() error { 79 | if len(config.Schedule) > 0 { 80 | if dur, err := config.ScheduleDuration(); dur == nil || err != nil { 81 | return errors.New("Provide a valid duration for the scheduled attack") 82 | } 83 | } 84 | return nil 85 | } 86 | 87 | func (config *CommonAttackConfig) GetUID() string { 88 | return config.UID 89 | } 90 | -------------------------------------------------------------------------------- /cmd/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "strings" 18 | 19 | _ "github.com/alecthomas/template" 20 | "github.com/pingcap/log" 21 | "github.com/spf13/cobra" 22 | _ "github.com/swaggo/swag" 23 | "go.uber.org/zap" 24 | ctrl "sigs.k8s.io/controller-runtime" 25 | ctrlzap "sigs.k8s.io/controller-runtime/pkg/log/zap" 26 | 27 | "github.com/chaos-mesh/chaosd/cmd/attack" 28 | "github.com/chaos-mesh/chaosd/cmd/completion" 29 | "github.com/chaos-mesh/chaosd/cmd/recover" 30 | "github.com/chaos-mesh/chaosd/cmd/search" 31 | "github.com/chaos-mesh/chaosd/cmd/server" 32 | "github.com/chaos-mesh/chaosd/cmd/version" 33 | "github.com/chaos-mesh/chaosd/pkg/utils" 34 | ) 35 | 36 | var logLevel string 37 | 38 | // CommandFlags are flags that used in all Commands 39 | var rootCmd = &cobra.Command{ 40 | Use: "chaosd", 41 | Short: "A command line client to run chaos experiment", 42 | } 43 | 44 | func init() { 45 | cobra.OnInitialize(setLog) 46 | rootCmd.PersistentFlags().StringVarP(&logLevel, "log-level", "", "", "the log level of chaosd. The value can be 'debug', 'info', 'warn' and 'error'") 47 | 48 | rootCmd.AddCommand( 49 | server.NewServerCommand(), 50 | attack.NewAttackCommand(), 51 | recover.NewRecoverCommand(), 52 | search.NewSearchCommand(), 53 | version.NewVersionCommand(), 54 | completion.NewCompletionCommand(), 55 | ) 56 | 57 | _ = utils.SetRuntimeEnv() 58 | } 59 | 60 | func setLog() { 61 | conf := &log.Config{Level: logLevel} 62 | lg, r, err := log.InitLogger(conf) 63 | if err != nil { 64 | log.Error("fail to init log", zap.Error(err)) 65 | return 66 | } 67 | log.ReplaceGlobals(lg, r) 68 | 69 | // set log of controller-runtime, so that can print logs in chaos mesh 70 | ctrl.SetLogger(ctrlzap.New(ctrlzap.UseDevMode(true))) 71 | 72 | // only in debug mode print log of go.uber.org/fx 73 | if strings.ToLower(logLevel) == "debug" { 74 | utils.PrintFxLog = true 75 | } 76 | } 77 | 78 | func main() { 79 | if err := rootCmd.Execute(); err != nil { 80 | utils.ExitWithError(utils.ExitError, err) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /pkg/utils/grpc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "context" 18 | "fmt" 19 | "time" 20 | 21 | "go.uber.org/zap" 22 | "google.golang.org/grpc" 23 | 24 | v1 "k8s.io/api/core/v1" 25 | "k8s.io/apimachinery/pkg/types" 26 | 27 | "github.com/pingcap/log" 28 | 29 | "sigs.k8s.io/controller-runtime/pkg/client" 30 | ) 31 | 32 | // DefaultRPCTimeout specifies default timeout of RPC between controller and chaos-operator 33 | const DefaultRPCTimeout = 60 * time.Second 34 | 35 | // RPCTimeout specifies timeout of RPC between controller and chaos-operator 36 | var RPCTimeout = DefaultRPCTimeout 37 | 38 | // CreateGrpcConnection create a grpc connection with given port 39 | func CreateGrpcConnection(ctx context.Context, c client.Client, pod *v1.Pod, port int) (*grpc.ClientConn, error) { 40 | nodeName := pod.Spec.NodeName 41 | log.Debug("Creating client to chaos-daemon", zap.String("node", nodeName)) 42 | 43 | var node v1.Node 44 | err := c.Get(ctx, types.NamespacedName{ 45 | Name: nodeName, 46 | }, &node) 47 | if err != nil { 48 | return nil, err 49 | } 50 | 51 | conn, err := grpc.Dial(fmt.Sprintf("%s:%d", node.Status.Addresses[0].Address, port), 52 | grpc.WithInsecure(), 53 | grpc.WithUnaryInterceptor(TimeoutClientInterceptor)) 54 | if err != nil { 55 | return nil, err 56 | } 57 | return conn, nil 58 | } 59 | 60 | // TimeoutClientInterceptor wraps the RPC with a timeout. 61 | func TimeoutClientInterceptor(ctx context.Context, method string, req, reply interface{}, 62 | cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { 63 | ctx, cancel := context.WithTimeout(ctx, RPCTimeout) 64 | defer cancel() 65 | return invoker(ctx, method, req, reply, cc, opts...) 66 | } 67 | 68 | // TimeoutServerInterceptor ensures the context is intact before handling over the 69 | // request to application. 70 | func TimeoutServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, 71 | handler grpc.UnaryHandler) (interface{}, error) { 72 | if ctx.Err() != nil { 73 | return nil, ctx.Err() 74 | } 75 | return handler(ctx, req) 76 | } 77 | -------------------------------------------------------------------------------- /pkg/utils/pool_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2023 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package utils 15 | 16 | import ( 17 | "context" 18 | "math" 19 | "testing" 20 | "time" 21 | 22 | "github.com/pingcap/log" 23 | "github.com/stretchr/testify/assert" 24 | "go.uber.org/zap" 25 | ) 26 | 27 | func TestCommandPools_Cancel(t *testing.T) { 28 | now := time.Now() 29 | cmdPools := NewCommandPools(context.Background(), nil, 1) 30 | var gErr []error 31 | runner := NewCommandRunner("sleep", []string{"10s"}). 32 | WithOutputHandler(func(output []byte, err error, _ chan interface{}) { 33 | if err != nil { 34 | log.Error(string(output), zap.Error(err)) 35 | gErr = append(gErr, err) 36 | } 37 | log.Info(string(output)) 38 | }, nil) 39 | cmdPools.Start(runner) 40 | cmdPools.Close() 41 | assert.Less(t, time.Since(now).Seconds(), 10.0) 42 | assert.Equal(t, 1, len(gErr)) 43 | } 44 | 45 | func TestCommandPools_Deadline(t *testing.T) { 46 | now := time.Now() 47 | deadline := time.Now().Add(time.Millisecond * 50) 48 | cmdPools := NewCommandPools(context.Background(), &deadline, 1) 49 | var gErr []error 50 | runner := NewCommandRunner("sleep", []string{"10s"}). 51 | WithOutputHandler(func(output []byte, err error, _ chan interface{}) { 52 | if err != nil { 53 | log.Error(string(output), zap.Error(err)) 54 | gErr = append(gErr, err) 55 | } 56 | log.Info(string(output)) 57 | }, nil) 58 | cmdPools.Start(runner) 59 | cmdPools.Wait() 60 | assert.Less(t, math.Abs(float64(time.Since(now).Milliseconds()-50)), 10.0) 61 | assert.Equal(t, 1, len(gErr)) 62 | 63 | } 64 | 65 | func TestCommandPools_Normal(t *testing.T) { 66 | now := time.Now() 67 | cmdPools := NewCommandPools(context.Background(), nil, 1) 68 | var gErr []error 69 | runner := NewCommandRunner("sleep", []string{"1s"}). 70 | WithOutputHandler(func(output []byte, err error, _ chan interface{}) { 71 | if err != nil { 72 | log.Error(string(output), zap.Error(err)) 73 | gErr = append(gErr, err) 74 | } 75 | log.Info(string(output)) 76 | }, nil) 77 | cmdPools.Start(runner) 78 | cmdPools.Wait() 79 | assert.Less(t, time.Since(now).Seconds(), 2.0) 80 | assert.Equal(t, 0, len(gErr)) 81 | } 82 | -------------------------------------------------------------------------------- /cmd/attack/host.go: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package attack 15 | 16 | import ( 17 | "fmt" 18 | 19 | "github.com/spf13/cobra" 20 | "go.uber.org/fx" 21 | 22 | "github.com/chaos-mesh/chaosd/cmd/server" 23 | "github.com/chaos-mesh/chaosd/pkg/core" 24 | "github.com/chaos-mesh/chaosd/pkg/server/chaosd" 25 | "github.com/chaos-mesh/chaosd/pkg/utils" 26 | ) 27 | 28 | func NewHostAttackCommand(uid *string) *cobra.Command { 29 | options := core.NewHostCommand() 30 | dep := fx.Options( 31 | server.Module, 32 | fx.Provide(func() *core.HostCommand { 33 | options.UID = *uid 34 | return options 35 | }), 36 | ) 37 | 38 | cmd := &cobra.Command{ 39 | Use: "host ", 40 | Short: "Host attack related commands", 41 | } 42 | 43 | cmd.AddCommand(NewHostShutdownCommand(dep, options)) 44 | cmd.AddCommand(NewHostRebootCommand(dep, options)) 45 | 46 | return cmd 47 | } 48 | 49 | func NewHostShutdownCommand(dep fx.Option, options *core.HostCommand) *cobra.Command { 50 | cmd := &cobra.Command{ 51 | Use: "shutdown", 52 | Short: "shutdowns system, this action will trigger shutdown of the host machine", 53 | 54 | Run: func(*cobra.Command, []string) { 55 | options.Action = core.HostShutdownAction 56 | utils.FxNewAppWithoutLog(dep, fx.Invoke(hostAttackF)).Run() 57 | }, 58 | } 59 | 60 | return cmd 61 | } 62 | 63 | func NewHostRebootCommand(dep fx.Option, options *core.HostCommand) *cobra.Command { 64 | cmd := &cobra.Command{ 65 | Use: "reboot", 66 | Short: "reboot system, this action will trigger reboot of the host machine", 67 | 68 | Run: func(*cobra.Command, []string) { 69 | options.Action = core.HostRebootAction 70 | utils.FxNewAppWithoutLog(dep, fx.Invoke(hostAttackF)).Run() 71 | }, 72 | } 73 | 74 | return cmd 75 | } 76 | 77 | func hostAttackF(chaos *chaosd.Server, options *core.HostCommand) { 78 | if err := options.Validate(); err != nil { 79 | utils.ExitWithError(utils.ExitBadArgs, err) 80 | } 81 | 82 | uid, err := chaos.ExecuteAttack(chaosd.HostAttack, options, core.CommandMode) 83 | if err != nil { 84 | utils.ExitWithError(utils.ExitError, err) 85 | } 86 | 87 | utils.NormalExit(fmt.Sprintf("Attack host successfully, uid: %s", uid)) 88 | } 89 | -------------------------------------------------------------------------------- /cmd/server/server.go: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Chaos Mesh Authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package server 15 | 16 | import ( 17 | "github.com/spf13/cobra" 18 | "go.uber.org/fx" 19 | 20 | "github.com/chaos-mesh/chaosd/pkg/config" 21 | "github.com/chaos-mesh/chaosd/pkg/server/httpserver" 22 | "github.com/chaos-mesh/chaosd/pkg/utils" 23 | "github.com/chaos-mesh/chaosd/pkg/version" 24 | ) 25 | 26 | func NewServerCommand() *cobra.Command { 27 | cmd := &cobra.Command{ 28 | Use: "server